def testFieldDefView_Normal(self):
     config = _MakeConfig()
     config.field_defs.append(self.approval_fd)
     config.approval_defs.append(self.approval_def)
     view = tracker_views.FieldDefView(self.field_def, config)
     self.assertEqual('AffectedUsers', view.field_name)
     self.assertEqual('descriptive docstring', view.docstring_short)
     self.assertEqual('INT_TYPE', view.type_name)
     self.assertEqual([], view.choices)
     self.assertEqual('required', view.importance)
     self.assertEqual(3, view.min_value)
     self.assertEqual(99, view.max_value)
     self.assertEqual('no_action', view.date_action_str)
     self.assertEqual(view.approval_id, 1)
     self.assertEqual(view.is_approval_subfield, ezt.boolean(True))
     self.assertEqual(view.approvers, [])
     self.assertEqual(view.survey, '')
     self.assertEqual(view.survey_questions, [])
     self.assertIsNone(view.is_phase_field)
Beispiel #2
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.
    """
        page_data = super(AdminLabels, self).GatherPageData(mr)
        config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
        field_def_views = [
            tracker_views.FieldDefView(fd, config)
            # TODO(jrobbins): future field-level view restrictions.
            for fd in config.field_defs if not fd.is_deleted
        ]
        page_data.update({
            'field_defs': field_def_views,
        })
        return page_data
Beispiel #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, field_def = self._GetFieldDef(mr)
    user_views = framework_views.MakeAllUserViews(
        mr.cnxn, self.services.user, field_def.admin_ids)
    field_def_view = tracker_views.FieldDefView(
        field_def, config, user_views=user_views)

    well_known_issue_types = tracker_helpers.FilterIssueTypes(config)

    allow_edit = permissions.CanEditFieldDef(
        mr.auth.effective_ids, mr.perms, mr.project, field_def)

    # Right now we do not allow renaming of enum fields.
    uneditable_name = field_def.field_type == tracker_pb2.FieldTypes.ENUM_TYPE

    initial_admins = ', '.join(sorted([
        uv.email for uv in field_def_view.admins]))

    return {
        'admin_tab_mode': servlet.Servlet.PROCESS_TAB_LABELS,
        'field_def': field_def_view,
        'allow_edit': ezt.boolean(allow_edit),
        'uneditable_name': ezt.boolean(uneditable_name),
        'initial_admins': initial_admins,
        'initial_applicable_type': field_def.applicable_type,
        'initial_applicable_predicate': field_def.applicable_predicate,
        'well_known_issue_types': well_known_issue_types,
        }
  def HandleRequest(self, mr):
    """Provide the UI with info used in auto-completion.

    Args:
      mr: common information parsed from the HTTP request.

    Returns:
      Results dictionary in JSON format
    """
    # Issue options data can be cached separately in each user's browser.  When
    # the project changes, a new cached_content_timestamp is set and it will
    # cause new requests to use a new URL.
    self.SetCacheHeaders(self.response)

    member_data = project_helpers.BuildProjectMembers(
        mr.cnxn, mr.project, self.services.user)
    owner_views = member_data['owners']
    committer_views = member_data['committers']
    contributor_views = member_data['contributors']

    config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)

    open_statuses = []
    closed_statuses = []
    for wks in config.well_known_statuses:
      if not wks.deprecated:
        item = dict(name=wks.status, doc=wks.status_docstring)
        if wks.means_open:
          open_statuses.append(item)
        else:
          closed_statuses.append(item)

    # TODO(jrobbins): restrictions on component definitions?
    components = [{'name': cd.path, 'doc': cd.docstring}
                  for cd in config.component_defs if not cd.deprecated]

    labels = []
    field_names = [
        fd.field_name for fd in config.field_defs if not fd.is_deleted]
    non_masked_labels = tracker_helpers.LabelsNotMaskedByFields(
        config, field_names)
    for wkl in non_masked_labels:
      if not wkl.commented:
        item = dict(name=wkl.name, doc=wkl.docstring)
        labels.append(item)

    # TODO(jrobbins): omit fields that they don't have permission to view.
    field_def_views = [
        tracker_views.FieldDefView(fd, config)
        for fd in config.field_defs
        if not fd.is_deleted]
    fields = [
        dict(field_name=fdv.field_name, field_type=fdv.field_type,
             field_id=fdv.field_id, needs_perm=fdv.needs_perm,
             is_required=fdv.is_required, is_multivalued=fdv.is_multivalued,
             choices=[dict(name=c.name, doc=c.docstring) for c in fdv.choices],
             docstring=fdv.docstring)
        for fdv in field_def_views]

    frequent_restrictions = _FREQUENT_ISSUE_RESTRICTIONS[:]
    custom_permissions = permissions.GetCustomPermissions(mr.project)
    if not custom_permissions:
      frequent_restrictions.extend(
          _EXAMPLE_ISSUE_RESTRICTIONS)

    labels.extend(_BuildRestrictionChoices(
        mr.project, frequent_restrictions,
        permissions.STANDARD_ISSUE_PERMISSIONS))

    group_ids = self.services.usergroup.DetermineWhichUserIDsAreGroups(
        mr.cnxn, [mem.user_id for mem in member_data['all_members']])
    logging.info('group_ids is %r', group_ids)

    acexclusion_ids = self.services.project.GetProjectAutocompleteExclusion(
        mr.cnxn, mr.project_id)

    # TODO(jrobbins): Normally, users will be allowed view the members
    # of any user group if the project From: email address is listed
    # as a group member, as well as any group that they are personally
    # members of.
    member_ids, owner_ids = self.services.usergroup.LookupVisibleMembers(
        mr.cnxn, group_ids, mr.perms, mr.auth.effective_ids, self.services)
    indirect_ids = set()
    for gid in group_ids:
      indirect_ids.update(member_ids.get(gid, []))
      indirect_ids.update(owner_ids.get(gid, []))
    indirect_user_ids = list(indirect_ids)
    indirect_member_views = framework_views.MakeAllUserViews(
        mr.cnxn, self.services.user, indirect_user_ids).values()

    visible_member_views = _FilterMemberData(
        mr, owner_views, committer_views, contributor_views,
        indirect_member_views)
    # Filter out servbice accounts
    visible_member_views = [m for m in visible_member_views
                            if not framework_helpers.IsServiceAccount(m.email)
                            and not m.user_id in acexclusion_ids]
    visible_member_email_list = list({
        uv.email for uv in visible_member_views})
    user_indexes = {email: idx
                    for idx, email in enumerate(visible_member_email_list)}
    visible_members_dict = {}
    for uv in visible_member_views:
      visible_members_dict[uv.email] = uv.user_id
    group_ids = self.services.usergroup.DetermineWhichUserIDsAreGroups(
        mr.cnxn, visible_members_dict.values())

    for field_dict in fields:
      needed_perm = field_dict['needs_perm']
      if needed_perm:
        qualified_user_indexes = []
        for uv in visible_member_views:
          # TODO(jrobbins): Similar code occurs in field_helpers.py.
          user = self.services.user.GetUser(mr.cnxn, uv.user_id)
          auth = monorailrequest.AuthData.FromUserID(
              mr.cnxn, uv.user_id, self.services)
          user_perms = permissions.GetPermissions(
              user, auth.effective_ids, mr.project)
          has_perm = user_perms.CanUsePerm(
              needed_perm, auth.effective_ids, mr.project, [])
          if has_perm:
            qualified_user_indexes.append(user_indexes[uv.email])

        field_dict['user_indexes'] = sorted(set(qualified_user_indexes))

    excl_prefixes = [prefix.lower() for prefix in
                     config.exclusive_label_prefixes]
    members_def_list = [dict(name=email, doc='')
                        for email in visible_member_email_list]
    members_def_list = sorted(
        members_def_list, key=lambda md: md['name'])
    for md in members_def_list:
      md_id = visible_members_dict[md['name']]
      if md_id in group_ids:
        md['is_group'] = True

    return {
        'open': open_statuses,
        'closed': closed_statuses,
        'statuses_offer_merge': config.statuses_offer_merge,
        'components': components,
        'labels': labels,
        'fields': fields,
        'excl_prefixes': excl_prefixes,
        'strict': ezt.boolean(config.restrict_to_known),
        'members': members_def_list,
        'custom_permissions': custom_permissions,
        }
Beispiel #5
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, field_def = self._GetFieldDef(mr)
        approval_def, subfields = None, []
        if field_def.field_type == tracker_pb2.FieldTypes.APPROVAL_TYPE:
            approval_def = tracker_bizobj.FindApprovalDefByID(
                field_def.field_id, config)
            user_views = framework_views.MakeAllUserViews(
                mr.cnxn, self.services.user, field_def.admin_ids,
                approval_def.approver_ids)
            subfields = tracker_bizobj.FindApprovalsSubfields(
                [field_def.field_id], config)[field_def.field_id]
        else:
            user_views = framework_views.MakeAllUserViews(
                mr.cnxn, self.services.user, field_def.admin_ids)
        field_def_view = tracker_views.FieldDefView(field_def,
                                                    config,
                                                    user_views=user_views,
                                                    approval_def=approval_def)

        well_known_issue_types = tracker_helpers.FilterIssueTypes(config)

        allow_edit = permissions.CanEditFieldDef(mr.auth.effective_ids,
                                                 mr.perms, mr.project,
                                                 field_def)

        # Right now we do not allow renaming of enum fields.
        _uneditable_name = field_def.field_type == tracker_pb2.FieldTypes.ENUM_TYPE

        initial_choices = '\n'.join([
            choice.name if not choice.docstring else
            (choice.name + ' = ' + choice.docstring)
            for choice in field_def_view.choices
        ])

        initial_approvers = ', '.join(
            sorted([
                approver_view.email
                for approver_view in field_def_view.approvers
            ]))

        initial_admins = ', '.join(
            sorted([uv.email for uv in field_def_view.admins]))

        return {
            'admin_tab_mode': servlet.Servlet.PROCESS_TAB_LABELS,
            'field_def': field_def_view,
            'allow_edit': ezt.boolean(allow_edit),
            # TODO(jojwang): update when name changes are actually saved
            'uneditable_name': ezt.boolean(True),
            'initial_admins': initial_admins,
            'initial_applicable_type': field_def.applicable_type,
            'initial_applicable_predicate': field_def.applicable_predicate,
            'initial_approvers': initial_approvers,
            'initial_choices': initial_choices,
            'approval_subfields':
            [fd for fd in subfields if not fd.is_deleted],
            'well_known_issue_types': well_known_issue_types,
        }
Beispiel #6
0
    def _ProcessEditField(self, mr, post_data, config, field_def):
        """The user wants to edit this field definition."""
        # TODO(jrobbins): future feature: editable field names

        parsed = field_helpers.ParseFieldDefRequest(post_data, config)

        if (parsed.min_value is not None and parsed.max_value is not None
                and parsed.min_value > parsed.max_value):
            mr.errors.min_value = 'Minimum value must be less than maximum.'

        if parsed.regex:
            try:
                re.compile(parsed.regex)
            except re.error:
                mr.errors.regex = 'Invalid regular expression.'

        admin_ids, admin_str = tracker_helpers.ParseAdminUsers(
            mr.cnxn, post_data['admin_names'], self.services.user)

        if field_def.field_type == tracker_pb2.FieldTypes.APPROVAL_TYPE:
            if parsed.approvers_str:
                approver_ids_dict = self.services.user.LookupUserIDs(
                    mr.cnxn,
                    re.split('[,;\s]+', parsed.approvers_str),
                    autocreate=True)
                approver_ids = list(set(approver_ids_dict.values()))
            else:
                mr.errors.approvers = 'Please provide at least one default approver.'

        if mr.errors.AnyErrors():
            new_field_def = field_helpers.ReviseFieldDefFromParsed(
                parsed, field_def)

            new_field_def_view = tracker_views.FieldDefView(
                new_field_def, config)

            self.PleaseCorrect(mr,
                               field_def=new_field_def_view,
                               initial_applicable_type=parsed.applicable_type,
                               initial_choices=parsed.choices_text,
                               initial_admins=admin_str,
                               initial_approvers=parsed.approvers_str)
            return

        self.services.config.UpdateFieldDef(
            mr.cnxn,
            mr.project_id,
            field_def.field_id,
            applicable_type=parsed.applicable_type,
            applicable_predicate=parsed.applicable_predicate,
            is_required=parsed.is_required,
            is_niche=parsed.is_niche,
            min_value=parsed.min_value,
            max_value=parsed.max_value,
            regex=parsed.regex,
            needs_member=parsed.needs_member,
            needs_perm=parsed.needs_perm,
            grants_perm=parsed.grants_perm,
            notify_on=parsed.notify_on,
            is_multivalued=parsed.is_multivalued,
            date_action=parsed.date_action_str,
            docstring=parsed.field_docstring,
            admin_ids=admin_ids)

        if field_def.field_type == tracker_pb2.FieldTypes.APPROVAL_TYPE:
            approval_defs = field_helpers.ReviseApprovals(
                field_def.field_id, approver_ids, parsed.survey, config)
            self.services.config.UpdateConfig(mr.cnxn,
                                              mr.project,
                                              approval_defs=approval_defs)

        if field_def.field_type == tracker_pb2.FieldTypes.ENUM_TYPE:
            self.services.config.UpdateConfig(
                mr.cnxn, mr.project, well_known_labels=parsed.revised_labels)

        return framework_helpers.FormatAbsoluteURL(mr,
                                                   urls.FIELD_DETAIL,
                                                   field=field_def.field_name,
                                                   saved=1,
                                                   ts=int(time.time()))