예제 #1
0
  def ProcessFormData(self, mr, post_data):
    """Validate and store the contents of the issues tracker admin page.

    Args:
      mr: commonly used info parsed from the request.
      post_data: HTML form data from the request.

    Returns:
      String URL to redirect the user to, or None if response was already sent.
    """
    config, component_def = self._GetComponentDef(mr)
    allow_edit = permissions.CanEditComponentDef(
        mr.auth.effective_ids, mr.perms, mr.project, component_def, config)
    if not allow_edit:
      raise permissions.PermissionException(
          'User is not allowed to edit or delete this component')

    if 'deletecomponent' in post_data:
      allow_delete = not tracker_bizobj.FindDescendantComponents(
          config, component_def)
      if not allow_delete:
        raise permissions.PermissionException(
            'User tried to delete component that had subcomponents')
      return self._ProcessDeleteComponent(mr, component_def)

    else:
      return self._ProcessEditComponent(mr, post_data, config, component_def)
예제 #2
0
  def components_delete(self, request):
    """Delete a component."""
    mar = self.mar_factory(request)
    config = self._services.config.GetProjectConfig(mar.cnxn, mar.project_id)
    component_path = request.componentPath
    component_def = tracker_bizobj.FindComponentDef(
        component_path, config)
    if not component_def:
      raise config_svc.NoSuchComponentException(
          'The component %s does not exist.' % component_path)
    if not permissions.CanViewComponentDef(
        mar.auth.effective_ids, mar.perms, mar.project, component_def):
      raise permissions.PermissionException(
          'User is not allowed to view this component %s' % component_path)
    if not permissions.CanEditComponentDef(
        mar.auth.effective_ids, mar.perms, mar.project, component_def, config):
      raise permissions.PermissionException(
          'User is not allowed to delete this component %s' % component_path)

    allow_delete = not tracker_bizobj.FindDescendantComponents(
        config, component_def)
    if not allow_delete:
      raise permissions.PermissionException(
          'User tried to delete component that had subcomponents')

    self._services.issue.DeleteComponentReferences(
        mar.cnxn, component_def.component_id)
    self._services.config.DeleteComponentDef(
        mar.cnxn, mar.project_id, component_def.component_id)
    return message_types.VoidMessage()
예제 #3
0
    def GatherPageData(self, mr):
        """Build up a dictionary of data values to use when rendering the page.

    Args:
      mr: commonly used info parsed from the request.

    Returns:
      Dict of values used by EZT for rendering the page.
    """
        config, component_def = self._GetComponentDef(mr)
        users_by_id = framework_views.MakeAllUserViews(mr.cnxn,
                                                       self.services.user,
                                                       component_def.admin_ids,
                                                       component_def.cc_ids)
        component_def_view = tracker_views.ComponentDefView(
            mr.cnxn, self.services, component_def, users_by_id)
        initial_admins = [
            users_by_id[uid].email for uid in component_def.admin_ids
        ]
        initial_cc = [users_by_id[uid].email for uid in component_def.cc_ids]
        initial_labels = [
            self.services.config.LookupLabel(mr.cnxn, mr.project_id, label_id)
            for label_id in component_def.label_ids
        ]

        creator, created = self._GetUserViewAndFormattedTime(
            mr, component_def.creator_id, component_def.created)
        modifier, modified = self._GetUserViewAndFormattedTime(
            mr, component_def.modifier_id, component_def.modified)

        allow_edit = permissions.CanEditComponentDef(mr.auth.effective_ids,
                                                     mr.perms, mr.project,
                                                     component_def, config)

        subcomponents = tracker_bizobj.FindDescendantComponents(
            config, component_def)
        templates = self.services.config.TemplatesWithComponent(
            mr.cnxn, component_def.component_id, config)
        allow_delete = allow_edit and not subcomponents and not templates

        return {
            'admin_tab_mode': servlet.Servlet.PROCESS_TAB_COMPONENTS,
            'component_def': component_def_view,
            'initial_leaf_name': component_def_view.leaf_name,
            'initial_docstring': component_def.docstring,
            'initial_deprecated': ezt.boolean(component_def.deprecated),
            'initial_admins': initial_admins,
            'initial_cc': initial_cc,
            'initial_labels': initial_labels,
            'allow_edit': ezt.boolean(allow_edit),
            'allow_delete': ezt.boolean(allow_delete),
            'subcomponents': subcomponents,
            'templates': templates,
            'creator': creator,
            'created': created,
            'modifier': modifier,
            'modified': modified,
        }
예제 #4
0
  def components_create(self, request):
    """Create a component."""
    mar = self.mar_factory(request)
    if not mar.perms.CanUsePerm(
        permissions.EDIT_PROJECT, mar.auth.effective_ids, mar.project, []):
      raise permissions.PermissionException(
          'User is not allowed to create components for this project')

    config = self._services.config.GetProjectConfig(mar.cnxn, mar.project_id)
    leaf_name = request.componentName
    if not tracker_constants.COMPONENT_NAME_RE.match(leaf_name):
      raise config_svc.InvalidComponentNameException(
          'The component name %s is invalid.' % leaf_name)

    parent_path = request.parentPath
    if parent_path:
      parent_def = tracker_bizobj.FindComponentDef(parent_path, config)
      if not parent_def:
        raise config_svc.NoSuchComponentException(
            'Parent component %s does not exist.' % parent_path)
      if not permissions.CanEditComponentDef(
          mar.auth.effective_ids, mar.perms, mar.project, parent_def, config):
        raise permissions.PermissionException(
            'User is not allowed to add a subcomponent to component %s' %
            parent_path)

      path = '%s>%s' % (parent_path, leaf_name)
    else:
      path = leaf_name

    if tracker_bizobj.FindComponentDef(path, config):
      raise config_svc.InvalidComponentNameException(
          'The name %s is already in use.' % path)

    created = int(time.time())
    user_emails = set()
    user_emails.update([mar.auth.email] + request.admin + request.cc)
    user_ids_dict = self._services.user.LookupUserIDs(
        mar.cnxn, list(user_emails), autocreate=False)
    admin_ids = [user_ids_dict[uname] for uname in request.admin]
    cc_ids = [user_ids_dict[uname] for uname in request.cc]
    label_ids = []  # TODO(jrobbins): allow API clients to specify this too.

    component_id = self._services.config.CreateComponentDef(
        mar.cnxn, mar.project_id, path, request.description, request.deprecated,
        admin_ids, cc_ids, created, user_ids_dict[mar.auth.email], label_ids)

    return api_pb2_v1.Component(
        componentId=component_id,
        projectName=request.projectId,
        componentPath=path,
        description=request.description,
        admin=request.admin,
        cc=request.cc,
        deprecated=request.deprecated,
        created=datetime.datetime.fromtimestamp(created),
        creator=mar.auth.email)
예제 #5
0
    def ProcessFormData(self, mr, post_data):
        """Processes a POST command to delete components.

    Args:
      mr: commonly used info parsed from the request.
      post_data: HTML form data from the request.

    Returns:
      String URL to redirect the user to, or None if response was already sent.
    """
        config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
        component_defs = self._GetComponentDefs(mr, post_data, config)
        # Reverse the component_defs so that we start deleting from subcomponents.
        component_defs.reverse()

        # Collect errors.
        perm_errors = []
        subcomponents_errors = []
        templates_errors = []
        # Collect successes.
        deleted_components = []

        for component_def in component_defs:
            allow_edit = permissions.CanEditComponentDef(
                mr.auth.effective_ids, mr.perms, mr.project, component_def,
                config)
            if not allow_edit:
                perm_errors.append(component_def.path)

            subcomponents = tracker_bizobj.FindDescendantComponents(
                config, component_def)
            if subcomponents:
                subcomponents_errors.append(component_def.path)

            templates = self.services.template.TemplatesWithComponent(
                mr.cnxn, component_def.component_id)
            if templates:
                templates_errors.append(component_def.path)

            allow_delete = allow_edit and not subcomponents and not templates
            if allow_delete:
                self._ProcessDeleteComponent(mr, component_def)
                deleted_components.append(component_def.path)
                # Refresh project config after the component deletion.
                config = self.services.config.GetProjectConfig(
                    mr.cnxn, mr.project_id)

        return framework_helpers.FormatAbsoluteURL(
            mr,
            urls.ADMIN_COMPONENTS,
            ts=int(time.time()),
            failed_perm=','.join(perm_errors),
            failed_subcomp=','.join(subcomponents_errors),
            failed_templ=','.join(templates_errors),
            deleted=','.join(deleted_components))
예제 #6
0
    def ProcessFormData(self, mr, post_data):
        """Validate and store the contents of the issues tracker admin page.

    Args:
      mr: commonly used info parsed from the request.
      post_data: HTML form data from the request.

    Returns:
      String URL to redirect the user to, or None if response was already sent.
    """
        config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
        parent_path = post_data.get('parent_path', '')
        parsed = component_helpers.ParseComponentRequest(
            mr, post_data, self.services)

        if parent_path:
            parent_def = tracker_bizobj.FindComponentDef(parent_path, config)
            if not parent_def:
                self.abort(500, 'parent component not found')
            allow_parent_edit = permissions.CanEditComponentDef(
                mr.auth.effective_ids, mr.perms, mr.project, parent_def,
                config)
            if not allow_parent_edit:
                raise permissions.PermissionException(
                    'User is not allowed to add a subcomponent here')

            path = '%s>%s' % (parent_path, parsed.leaf_name)
        else:
            path = parsed.leaf_name

        leaf_name_error_msg = LeafNameErrorMessage(parent_path,
                                                   parsed.leaf_name, config)
        if leaf_name_error_msg:
            mr.errors.leaf_name = leaf_name_error_msg

        if mr.errors.AnyErrors():
            self.PleaseCorrect(
                mr,
                parent_path=parent_path,
                initial_leaf_name=parsed.leaf_name,
                initial_docstring=parsed.docstring,
                initial_deprecated=ezt.boolean(parsed.deprecated),
                initial_admins=parsed.admin_usernames,
                initial_cc=parsed.cc_usernames,
                initial_labels=parsed.label_strs,
            )
            return

        created = int(time.time())
        creator_id = self.services.user.LookupUserID(mr.cnxn,
                                                     mr.auth.email,
                                                     autocreate=False)

        self.services.config.CreateComponentDef(mr.cnxn,
                                                mr.project_id,
                                                path,
                                                parsed.docstring,
                                                parsed.deprecated,
                                                parsed.admin_ids,
                                                parsed.cc_ids,
                                                created,
                                                creator_id,
                                                label_ids=parsed.label_ids)

        return framework_helpers.FormatAbsoluteURL(mr,
                                                   urls.ADMIN_COMPONENTS,
                                                   saved=1,
                                                   ts=int(time.time()))
예제 #7
0
  def components_update(self, request):
    """Update a component."""
    mar = self.mar_factory(request)
    config = self._services.config.GetProjectConfig(mar.cnxn, mar.project_id)
    component_path = request.componentPath
    component_def = tracker_bizobj.FindComponentDef(
        component_path, config)
    if not component_def:
      raise config_svc.NoSuchComponentException(
          'The component %s does not exist.' % component_path)
    if not permissions.CanViewComponentDef(
        mar.auth.effective_ids, mar.perms, mar.project, component_def):
      raise permissions.PermissionException(
          'User is not allowed to view this component %s' % component_path)
    if not permissions.CanEditComponentDef(
        mar.auth.effective_ids, mar.perms, mar.project, component_def, config):
      raise permissions.PermissionException(
          'User is not allowed to edit this component %s' % component_path)

    original_path = component_def.path
    new_path = component_def.path
    new_docstring = component_def.docstring
    new_deprecated = component_def.deprecated
    new_admin_ids = component_def.admin_ids
    new_cc_ids = component_def.cc_ids
    update_filterrule = False
    for update in request.updates:
      if update.field == api_pb2_v1.ComponentUpdateFieldID.LEAF_NAME:
        leaf_name = update.leafName
        if not tracker_constants.COMPONENT_NAME_RE.match(leaf_name):
          raise config_svc.InvalidComponentNameException(
              'The component name %s is invalid.' % leaf_name)

        if '>' in original_path:
          parent_path = original_path[:original_path.rindex('>')]
          new_path = '%s>%s' % (parent_path, leaf_name)
        else:
          new_path = leaf_name

        conflict = tracker_bizobj.FindComponentDef(new_path, config)
        if conflict and conflict.component_id != component_def.component_id:
          raise config_svc.InvalidComponentNameException(
              'The name %s is already in use.' % new_path)
        update_filterrule = True
      elif update.field == api_pb2_v1.ComponentUpdateFieldID.DESCRIPTION:
        new_docstring = update.description
      elif update.field == api_pb2_v1.ComponentUpdateFieldID.ADMIN:
        user_ids_dict = self._services.user.LookupUserIDs(
            mar.cnxn, list(update.admin), autocreate=True)
        new_admin_ids = [user_ids_dict[email] for email in update.admin]
      elif update.field == api_pb2_v1.ComponentUpdateFieldID.CC:
        user_ids_dict = self._services.user.LookupUserIDs(
            mar.cnxn, list(update.cc), autocreate=True)
        new_cc_ids = [user_ids_dict[email] for email in update.cc]
        update_filterrule = True
      elif update.field == api_pb2_v1.ComponentUpdateFieldID.DEPRECATED:
        new_deprecated = update.deprecated
      else:
        logging.error('Unknown component field %r', update.field)

    new_modified = int(time.time())
    new_modifier_id = self._services.user.LookupUserID(
        mar.cnxn, mar.auth.email, autocreate=False)
    logging.info(
        'Updating component id %d: path-%s, docstring-%s, deprecated-%s,'
        ' admin_ids-%s, cc_ids-%s modified by %s', component_def.component_id,
        new_path, new_docstring, new_deprecated, new_admin_ids, new_cc_ids,
        new_modifier_id)
    self._services.config.UpdateComponentDef(
        mar.cnxn, mar.project_id, component_def.component_id,
        path=new_path, docstring=new_docstring, deprecated=new_deprecated,
        admin_ids=new_admin_ids, cc_ids=new_cc_ids, modified=new_modified,
        modifier_id=new_modifier_id)

    # TODO(sheyang): reuse the code in componentdetails
    if original_path != new_path:
      # If the name changed then update all of its subcomponents as well.
      subcomponent_ids = tracker_bizobj.FindMatchingComponentIDs(
          original_path, config, exact=False)
      for subcomponent_id in subcomponent_ids:
        if subcomponent_id == component_def.component_id:
          continue
        subcomponent_def = tracker_bizobj.FindComponentDefByID(
            subcomponent_id, config)
        subcomponent_new_path = subcomponent_def.path.replace(
            original_path, new_path, 1)
        self._services.config.UpdateComponentDef(
            mar.cnxn, mar.project_id, subcomponent_def.component_id,
            path=subcomponent_new_path)

    if update_filterrule:
      filterrules_helpers.RecomputeAllDerivedFields(
          mar.cnxn, self._services, mar.project, config)

    return message_types.VoidMessage()