Пример #1
0
  def testComponentsUpdate_Normal(self):
    self.services.project.TestAddProject(
        'test-project', owner_ids=[1],
        project_id=12345)
    self.SetUpComponents(12345, 1, 'API')
    self.SetUpComponents(12345, 2, 'Parent')
    self.SetUpComponents(12345, 3, 'Parent>Child')

    cd_dict = {
      'componentPath': 'API',
      'updates': [
          {'field': 'DESCRIPTION', 'description': ''},
          {'field': 'CC', 'cc': ['*****@*****.**', '*****@*****.**']},
          {'field': 'DEPRECATED', 'deprecated': True}]}
    self.request.update(cd_dict)
    _ = self.call_api('components_update', self.request).json_body
    component_def = tracker_bizobj.FindComponentDef(
        'API', self.config)
    self.assertIsNotNone(component_def)
    self.assertEqual('', component_def.docstring)
    self.assertEqual([1L, 2L], component_def.cc_ids)
    self.assertTrue(component_def.deprecated)

    cd_dict = {
      'componentPath': 'Parent',
      'updates': [
          {'field': 'LEAF_NAME', 'leafName': 'NewParent'}]}
    self.request.update(cd_dict)
    _ = self.call_api('components_update', self.request).json_body
    cd_parent = tracker_bizobj.FindComponentDef(
        'NewParent', self.config)
    cd_child = tracker_bizobj.FindComponentDef(
        'NewParent>Child', self.config)
    self.assertIsNotNone(cd_parent)
    self.assertIsNotNone(cd_child)
Пример #2
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)
Пример #3
0
    def testProcessEditComponent_RenameWithSubComponents(self):
        subcd_1 = tracker_bizobj.MakeComponentDef(2, self.project.project_id,
                                                  'BackEnd>Worker1', 'doc',
                                                  False, [], [111L], 0, 125L,
                                                  3, 126L)
        subcd_2 = tracker_bizobj.MakeComponentDef(3, self.project.project_id,
                                                  'BackEnd>Worker2', 'doc',
                                                  False, [], [111L], 0, 125L,
                                                  4, 127L)
        self.config.component_defs.extend([subcd_1, subcd_2])

        self.mox.StubOutWithMock(filterrules_helpers,
                                 'RecomputeAllDerivedFields')
        filterrules_helpers.RecomputeAllDerivedFields(self.mr.cnxn,
                                                      self.services,
                                                      self.mr.project,
                                                      self.config)
        self.mox.ReplayAll()
        post_data = fake.PostData(
            leaf_name=['BackEnds'],
            docstring=['This is where the magic happens'],
            deprecated=[True],
            admins=['*****@*****.**'],
            cc=['*****@*****.**'],
            labels=[''])

        self.servlet._ProcessEditComponent(self.mr, post_data, self.config,
                                           self.cd)

        self.mox.VerifyAll()
        config = self.services.config.GetProjectConfig(self.mr.cnxn,
                                                       self.mr.project_id)
        cd = tracker_bizobj.FindComponentDef('BackEnds', config)
        self.assertEqual('BackEnds', cd.path)
        subcd_1 = tracker_bizobj.FindComponentDef('BackEnds>Worker1', config)
        self.assertEqual('BackEnds>Worker1', subcd_1.path)
        # Assert that creator and modifier have not changed for subcd_1.
        self.assertEqual(125L, subcd_1.creator_id)
        self.assertEqual(0, subcd_1.created)
        self.assertEqual(126L, subcd_1.modifier_id)
        self.assertEqual(3, subcd_1.modified)

        subcd_2 = tracker_bizobj.FindComponentDef('BackEnds>Worker2', config)
        self.assertEqual('BackEnds>Worker2', subcd_2.path)
        # Assert that creator and modifier have not changed for subcd_2.
        self.assertEqual(125L, subcd_2.creator_id)
        self.assertEqual(0, subcd_2.created)
        self.assertEqual(127L, subcd_2.modifier_id)
        self.assertEqual(4, subcd_2.modified)
Пример #4
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()
Пример #5
0
    def testProcessEditComponent(self):
        post_data = fake.PostData(
            leaf_name=['BackEnd'],
            docstring=['This is where the magic happens'],
            deprecated=[True],
            admins=['*****@*****.**'],
            cc=['*****@*****.**'],
            labels=['Hot, Cold'])

        self.servlet._ProcessEditComponent(self.mr, post_data, self.config,
                                           self.cd)

        self.mox.VerifyAll()
        config = self.services.config.GetProjectConfig(self.mr.cnxn,
                                                       self.mr.project_id)
        cd = tracker_bizobj.FindComponentDef('BackEnd', config)
        self.assertEqual('BackEnd', cd.path)
        self.assertEqual('This is where the magic happens', cd.docstring)
        self.assertEqual(True, cd.deprecated)
        self.assertEqual([111L], cd.admin_ids)
        self.assertEqual([111L], cd.cc_ids)
        # Assert that creator and created were not updated.
        self.assertEqual(122L, cd.creator_id)
        self.assertEqual(100000, cd.created)
        # Assert that modifier and modified were updated.
        self.assertEqual(122L, cd.modifier_id)
        self.assertTrue(cd.modified > 10000000)
Пример #6
0
 def _GetComponentDef(self, mr):
   """Get the config and component definition to be viewed or edited."""
   if not mr.component_path:
     self.abort(404, 'component not specified')
   config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
   component_def = tracker_bizobj.FindComponentDef(mr.component_path, config)
   if not component_def:
     self.abort(404, 'component not found')
   return config, component_def
Пример #7
0
 def _GetComponentDefs(self, _mr, post_data, config):
     """Get the config and component definitions from the request."""
     component_defs = []
     component_paths = post_data.get('delete_components').split(',')
     for component_path in component_paths:
         component_def = tracker_bizobj.FindComponentDef(
             component_path, config)
         component_defs.append(component_def)
     return component_defs
Пример #8
0
def LookupComponentIDs(component_paths, config, errors):
    """Look up the IDs of the specified components in the given config."""
    component_ids = []
    for path in component_paths:
        if not path:
            continue
        cd = tracker_bizobj.FindComponentDef(path, config)
        if cd:
            component_ids.append(cd.component_id)
        else:
            errors.components = 'Unknown component %s' % path

    return component_ids
Пример #9
0
def LeafNameErrorMessage(parent_path, leaf_name, config):
    """Return an error message for the given component name, or None."""
    if not tracker_constants.COMPONENT_NAME_RE.match(leaf_name):
        return 'Invalid component name'

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

    if tracker_bizobj.FindComponentDef(path, config):
        return 'That name is already in use.'

    return None
    def testProcessFormData_Normal(self):
        post_data = fake.PostData(parent_path=['BackEnd'],
                                  leaf_name=['DB'],
                                  docstring=['A database'],
                                  deprecated=[False],
                                  admins=[''],
                                  cc=[''],
                                  labels=[''])
        url = self.servlet.ProcessFormData(self.mr, post_data)
        self.assertTrue('/adminComponents?saved=1&' in url)
        config = self.services.config.GetProjectConfig(self.mr.cnxn,
                                                       self.mr.project_id)

        cd = tracker_bizobj.FindComponentDef('BackEnd>DB', config)
        self.assertEqual('BackEnd>DB', cd.path)
        self.assertEqual('A database', cd.docstring)
        self.assertEqual([], cd.admin_ids)
        self.assertEqual([], cd.cc_ids)
        self.assertTrue(cd.created > 0)
        self.assertEqual(122L, cd.creator_id)
Пример #11
0
    def testProcessFormData_Edit(self):
        post_data = fake.PostData(
            leaf_name=['BackEnd'],
            docstring=['This is where the magic happens'],
            deprecated=[True],
            admins=['*****@*****.**'],
            cc=['*****@*****.**'],
            labels=['Hot, Cold'])

        url = self.servlet.ProcessFormData(self.mr, post_data)

        self.mox.VerifyAll()
        self.assertTrue('/components/detail?component=BackEnd&saved=1&' in url)
        config = self.services.config.GetProjectConfig(self.mr.cnxn,
                                                       self.mr.project_id)

        cd = tracker_bizobj.FindComponentDef('BackEnd', config)
        self.assertEqual('BackEnd', cd.path)
        self.assertEqual('This is where the magic happens', cd.docstring)
        self.assertEqual(True, cd.deprecated)
        self.assertEqual([111L], cd.admin_ids)
        self.assertEqual([111L], cd.cc_ids)
Пример #12
0
 def testFindComponentDef_MatchFound(self):
   config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
   cd = tracker_pb2.ComponentDef(path='UI>Splash')
   config.component_defs.append(cd)
   actual = tracker_bizobj.FindComponentDef('UI>Splash', config)
   self.assertEqual(cd, actual)
Пример #13
0
 def testFindComponentDef_Empty(self):
   config = tracker_bizobj.MakeDefaultProjectIssueConfig(789)
   actual = tracker_bizobj.FindComponentDef('DB', config)
   self.assertIsNone(actual)
Пример #14
0
  def _ProcessEditComponent(self, mr, post_data, config, component_def):
    """The user wants to edit this component definition."""
    parsed = component_helpers.ParseComponentRequest(
        mr, post_data, self.services)

    if not tracker_constants.COMPONENT_NAME_RE.match(parsed.leaf_name):
      mr.errors.leaf_name = 'Invalid component name'

    original_path = component_def.path
    if mr.component_path and '>' in mr.component_path:
      parent_path = mr.component_path[:mr.component_path.rindex('>')]
      new_path = '%s>%s' % (parent_path, parsed.leaf_name)
    else:
      new_path = parsed.leaf_name

    conflict = tracker_bizobj.FindComponentDef(new_path, config)
    if conflict and conflict.component_id != component_def.component_id:
      mr.errors.leaf_name = 'That name is already in use.'

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

    if mr.errors.AnyErrors():
      self.PleaseCorrect(
          mr, 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,
          created=created,
          creator=creator,
          modified=modified,
          modifier=modifier,
      )
      return None

    new_modified = int(time.time())
    new_modifier_id = self.services.user.LookupUserID(
        mr.cnxn, mr.auth.email, autocreate=False)
    self.services.config.UpdateComponentDef(
        mr.cnxn, mr.project_id, component_def.component_id,
        path=new_path, docstring=parsed.docstring, deprecated=parsed.deprecated,
        admin_ids=parsed.admin_ids, cc_ids=parsed.cc_ids, modified=new_modified,
        modifier_id=new_modifier_id, label_ids=parsed.label_ids)

    update_rule = False
    if new_path != original_path:
      update_rule = True
      # 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(
            mr.cnxn, mr.project_id, subcomponent_def.component_id,
            path=subcomponent_new_path)

    if (set(parsed.cc_ids) != set(component_def.cc_ids) or
        set(parsed.label_ids) != set(component_def.label_ids)):
      update_rule = True
    if update_rule:
      filterrules_helpers.RecomputeAllDerivedFields(
          mr.cnxn, self.services, mr.project, config)

    return framework_helpers.FormatAbsoluteURL(
        mr, urls.COMPONENT_DETAIL,
        component=new_path, saved=1, ts=int(time.time()))
Пример #15
0
 def testProcessDeleteComponent(self):
     self.servlet._ProcessDeleteComponent(self.mr, self.cd)
     self.assertIsNone(
         tracker_bizobj.FindComponentDef('BackEnd', self.config))
Пример #16
0
 def testProcessFormData_Delete(self):
     post_data = fake.PostData(name=['BackEnd'], deletecomponent=['Submit'])
     url = self.servlet.ProcessFormData(self.mr, post_data)
     self.assertTrue('/adminComponents?deleted=1&' in url)
     self.assertIsNone(
         tracker_bizobj.FindComponentDef('BackEnd', self.config))
Пример #17
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()))
Пример #18
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()