Example #1
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.
    """
        with mr.profiler.Phase('getting config'):
            config = self.services.config.GetProjectConfig(
                mr.cnxn, mr.project_id)

        # In addition to checking perms, we adjust some default field values for
        # project members.
        is_member = framework_bizobj.UserIsInProject(mr.project,
                                                     mr.auth.effective_ids)
        page_perms = self.MakePagePerms(
            mr, None, permissions.CREATE_ISSUE, permissions.SET_STAR,
            permissions.EDIT_ISSUE, permissions.EDIT_ISSUE_SUMMARY,
            permissions.EDIT_ISSUE_STATUS, permissions.EDIT_ISSUE_OWNER,
            permissions.EDIT_ISSUE_CC)

        with work_env.WorkEnv(mr, self.services) as we:
            userprefs = we.GetUserPrefs(mr.auth.user_id)
            code_font = any(
                pref for pref in userprefs.prefs
                if pref.name == 'code_font' and pref.value == 'true')

        template = self._GetTemplate(mr.cnxn, config, mr.template_name,
                                     is_member)

        if template.summary:
            initial_summary = template.summary
            initial_summary_must_be_edited = template.summary_must_be_edited
        else:
            initial_summary = PLACEHOLDER_SUMMARY
            initial_summary_must_be_edited = True

        if template.status:
            initial_status = template.status
        elif is_member:
            initial_status = 'Accepted'
        else:
            initial_status = 'New'  # not offering meta, only used in hidden field.

        component_paths = []
        for component_id in template.component_ids:
            component_paths.append(
                tracker_bizobj.FindComponentDefByID(component_id, config).path)
        initial_components = ', '.join(component_paths)

        if template.owner_id:
            initial_owner = framework_views.MakeUserView(
                mr.cnxn, self.services.user, template.owner_id)
        elif template.owner_defaults_to_member and page_perms.EditIssue:
            initial_owner = mr.auth.user_view
        else:
            initial_owner = None

        if initial_owner:
            initial_owner_name = initial_owner.email
            owner_avail_state = initial_owner.avail_state
            owner_avail_message_short = initial_owner.avail_message_short
        else:
            initial_owner_name = ''
            owner_avail_state = None
            owner_avail_message_short = None

        # Check whether to allow attachments from the entry page
        allow_attachments = tracker_helpers.IsUnderSoftAttachmentQuota(
            mr.project)

        config_view = tracker_views.ConfigView(mr, self.services, config,
                                               template)
        # If the user followed a link that specified the template name, make sure
        # that it is also in the menu as the current choice.
        # TODO(jeffcarp): Unit test this.
        config_view.template_view.can_view = ezt.boolean(True)

        # TODO(jeffcarp): Unit test this.
        offer_templates = len(config_view.template_names) > 1
        restrict_to_known = config.restrict_to_known
        enum_field_name_set = {
            fd.field_name.lower()
            for fd in config.field_defs
            if fd.field_type is tracker_pb2.FieldTypes.ENUM_TYPE
            and not fd.is_deleted
        }  # TODO(jrobbins): restrictions
        link_or_template_labels = mr.GetListParam('labels', template.labels)
        labels = [
            lab for lab in link_or_template_labels if
            not tracker_bizobj.LabelIsMaskedByField(lab, enum_field_name_set)
        ]

        # Corp-mode users automatically add R-V-G.
        with work_env.WorkEnv(mr, self.services) as we:
            userprefs = we.GetUserPrefs(mr.auth.user_id)
            corp_mode = any(
                up.name == 'restrict_new_issues' and up.value == 'true'
                for up in userprefs.prefs)
            if corp_mode:
                if not any(lab.lower().startswith('restrict-view-')
                           for lab in labels):
                    labels.append(CORP_RESTRICTION_LABEL)

        field_user_views = tracker_views.MakeFieldUserViews(
            mr.cnxn, template, self.services.user)
        approval_ids = [av.approval_id for av in template.approval_values]
        field_views = tracker_views.MakeAllFieldValueViews(
            config,
            link_or_template_labels, [],
            template.field_values,
            field_user_views,
            parent_approval_ids=approval_ids,
            phases=template.phases)
        # TODO(jojwang): monorail:6305, remove this hack when Edit perms for field
        # values are implemented.
        field_views = [
            view for view in field_views
            if view.field_name.lower() not in RESTRICTED_FLT_FIELDS
        ]

        # TODO(jrobbins): remove "or []" after next release.
        (prechecked_approvals, required_approval_ids,
         phases) = issue_tmpl_helpers.GatherApprovalsPageData(
             template.approval_values or [], template.phases, config)
        approvals = [
            view for view in field_views if view.field_id in approval_ids
        ]

        page_data = {
            'issue_tab_mode':
            'issueEntry',
            'initial_summary':
            initial_summary,
            'template_summary':
            initial_summary,
            'clear_summary_on_click':
            ezt.boolean(initial_summary_must_be_edited
                        and 'initial_summary' not in mr.form_overrides),
            'must_edit_summary':
            ezt.boolean(initial_summary_must_be_edited),
            'initial_description':
            template.content,
            'template_name':
            template.name,
            'component_required':
            ezt.boolean(template.component_required),
            'initial_status':
            initial_status,
            'initial_owner':
            initial_owner_name,
            'owner_avail_state':
            owner_avail_state,
            'owner_avail_message_short':
            owner_avail_message_short,
            'initial_components':
            initial_components,
            'initial_cc':
            '',
            'initial_blocked_on':
            '',
            'initial_blocking':
            '',
            'initial_hotlists':
            '',
            'labels':
            labels,
            'fields':
            field_views,
            'any_errors':
            ezt.boolean(mr.errors.AnyErrors()),
            'page_perms':
            page_perms,
            'allow_attachments':
            ezt.boolean(allow_attachments),
            'max_attach_size':
            template_helpers.BytesKbOrMb(
                framework_constants.MAX_POST_BODY_SIZE),
            'offer_templates':
            ezt.boolean(offer_templates),
            'config':
            config_view,
            'restrict_to_known':
            ezt.boolean(restrict_to_known),
            'is_member':
            ezt.boolean(is_member),
            'code_font':
            ezt.boolean(code_font),
            # The following are necessary for displaying phases that come with
            # this template. These are read-only.
            'allow_edit':
            ezt.boolean(False),
            'initial_phases':
            phases,
            'approvals':
            approvals,
            'prechecked_approvals':
            prechecked_approvals,
            'required_approval_ids':
            required_approval_ids,
            # See monorail:4692 and the use of PHASES_WITH_MILESTONES
            # in elements/flt/mr-launch-overview/mr-phase.js
            'issue_phase_names':
            list({
                phase.name.lower()
                for phase in phases if phase.name in PHASES_WITH_MILESTONES
            }),
        }

        return page_data
Example #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.
    """

        config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
        template = self.services.template.GetTemplateByName(
            mr.cnxn, mr.template_name, mr.project_id)
        template_view = tracker_views.IssueTemplateView(
            mr, template, self.services.user, config)
        with mr.profiler.Phase('making user views'):
            users_involved = tracker_bizobj.UsersInvolvedInTemplate(template)
            users_by_id = framework_views.MakeAllUserViews(
                mr.cnxn, self.services.user, users_involved)
            framework_views.RevealAllEmailsToMembers(mr.auth, mr.project,
                                                     users_by_id)
        field_name_set = {
            fd.field_name.lower()
            for fd in config.field_defs
            if fd.field_type is tracker_pb2.FieldTypes.ENUM_TYPE
            and not fd.is_deleted
        }
        non_masked_labels = tracker_bizobj.NonMaskedLabels(
            template.labels, field_name_set)

        field_views = tracker_views.MakeAllFieldValueViews(
            config,
            template.labels, [],
            template.field_values,
            users_by_id,
            phases=template.phases)

        (prechecked_approvals, required_approval_ids,
         initial_phases) = template_helpers.GatherApprovalsPageData(
             template.approval_values, template.phases, config)

        allow_edit = permissions.CanEditTemplate(mr.auth.effective_ids,
                                                 mr.perms, mr.project,
                                                 template)

        return {
            'admin_tab_mode':
            self._PROCESS_SUBTAB,
            'allow_edit':
            ezt.boolean(allow_edit),
            'new_template_form':
            ezt.boolean(False),
            'initial_members_only':
            template_view.members_only,
            'template_name':
            template_view.name,
            'initial_summary':
            template_view.summary,
            'initial_must_edit_summary':
            template_view.summary_must_be_edited,
            'initial_content':
            template_view.content,
            'initial_status':
            template_view.status,
            'initial_owner':
            template_view.ownername,
            'initial_owner_defaults_to_member':
            template_view.owner_defaults_to_member,
            'initial_components':
            template_view.components,
            'initial_component_required':
            template_view.component_required,
            'fields': [
                view for view in field_views
                if view.field_def.type_name is not 'APPROVAL_TYPE'
            ],
            'initial_add_approvals':
            ezt.boolean(prechecked_approvals),
            'initial_phases':
            initial_phases,
            'approvals': [
                view for view in field_views
                if view.field_def.type_name is 'APPROVAL_TYPE'
            ],
            'prechecked_approvals':
            prechecked_approvals,
            'required_approval_ids':
            required_approval_ids,
            'labels':
            non_masked_labels,
            'initial_admins':
            template_view.admin_names,
        }
Example #3
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)
        parsed = template_helpers.ParseTemplateRequest(post_data, config)
        field_helpers.ShiftEnumFieldsIntoLabels(parsed.labels, [],
                                                parsed.field_val_strs, [],
                                                config)
        template = self.services.template.GetTemplateByName(
            mr.cnxn, parsed.name, mr.project_id)
        allow_edit = permissions.CanEditTemplate(mr.auth.effective_ids,
                                                 mr.perms, mr.project,
                                                 template)
        if not allow_edit:
            raise permissions.PermissionException(
                'User is not allowed edit this issue template.')

        if 'deletetemplate' in post_data:
            self.services.template.DeleteIssueTemplateDef(
                mr.cnxn, mr.project_id, template.template_id)
            return framework_helpers.FormatAbsoluteURL(mr,
                                                       urls.ADMIN_TEMPLATES,
                                                       deleted=1,
                                                       ts=int(time.time()))

        (admin_ids, owner_id, component_ids, field_values, phases,
         approvals) = template_helpers.GetTemplateInfoFromParsed(
             mr, self.services, parsed, config)

        if mr.errors.AnyErrors():
            field_views = tracker_views.MakeAllFieldValueViews(
                config, [], [], field_values, {})

            prechecked_approvals = template_helpers.GetCheckedApprovalsFromParsed(
                parsed.approvals_to_phase_idx)

            self.PleaseCorrect(
                mr,
                initial_members_only=ezt.boolean(parsed.members_only),
                template_name=parsed.name,
                initial_summary=parsed.summary,
                initial_must_edit_summary=ezt.boolean(
                    parsed.summary_must_be_edited),
                initial_content=parsed.content,
                initial_status=parsed.status,
                initial_owner=parsed.owner_str,
                initial_owner_defaults_to_member=ezt.boolean(
                    parsed.owner_defaults_to_member),
                initial_components=', '.join(parsed.component_paths),
                initial_component_required=ezt.boolean(
                    parsed.component_required),
                initial_admins=parsed.admin_str,
                labels=parsed.labels,
                fields=[
                    view for view in field_views
                    if view.field_def.type_name is not 'APPROVAL_TYPE'
                ],
                initial_add_approvals=ezt.boolean(parsed.add_approvals),
                initial_phases=[
                    tracker_pb2.Phase(name=name) for name in parsed.phase_names
                ],
                approvals=[
                    view for view in field_views
                    if view.field_def.type_name is 'APPROVAL_TYPE'
                ],
                prechecked_approvals=prechecked_approvals,
                required_approval_ids=parsed.required_approval_ids)
            return

        labels = [label for label in parsed.labels if label]
        self.services.template.UpdateIssueTemplateDef(
            mr.cnxn,
            mr.project_id,
            template.template_id,
            name=parsed.name,
            content=parsed.content,
            summary=parsed.summary,
            summary_must_be_edited=parsed.summary_must_be_edited,
            status=parsed.status,
            members_only=parsed.members_only,
            owner_defaults_to_member=parsed.owner_defaults_to_member,
            component_required=parsed.component_required,
            owner_id=owner_id,
            labels=labels,
            component_ids=component_ids,
            admin_ids=admin_ids,
            field_values=field_values,
            phases=phases,
            approval_values=approvals)

        return framework_helpers.FormatAbsoluteURL(mr,
                                                   urls.TEMPLATE_DETAIL,
                                                   template=template.name,
                                                   saved=1,
                                                   ts=int(time.time()))
Example #4
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.
    """
        with mr.profiler.Phase('getting issues'):
            if not mr.local_id_list:
                raise exceptions.InputException()
            requested_issues = self.services.issue.GetIssuesByLocalIDs(
                mr.cnxn, mr.project_id, sorted(mr.local_id_list))

        with mr.profiler.Phase('filtering issues'):
            # TODO(jrobbins): filter out issues that the user cannot edit and
            # provide that as feedback rather than just siliently ignoring them.
            open_issues, closed_issues = (
                tracker_helpers.GetAllowedOpenedAndClosedIssues(
                    mr, [issue.issue_id for issue in requested_issues],
                    self.services))
            issues = open_issues + closed_issues

        if not issues:
            self.abort(404, 'no issues found')

        config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
        type_label_set = {
            lab.lower()
            for lab in issues[0].labels if lab.lower().startswith('type-')
        }
        for issue in issues[1:]:
            new_type_set = {
                lab.lower()
                for lab in issue.labels if lab.lower().startswith('type-')
            }
            type_label_set &= new_type_set

        issue_phases = list(
            itertools.chain.from_iterable(issue.phases for issue in issues))

        field_views = tracker_views.MakeAllFieldValueViews(config,
                                                           type_label_set, [],
                                                           [], {},
                                                           phases=issue_phases)
        # Explicitly set all field views to not required. We do not want to force
        # users to have to set it for issues missing required fields.
        # See https://bugs.chromium.org/p/monorail/issues/detail?id=500 for more
        # details.
        for fv in field_views:
            fv.field_def.is_required_bool = None

        with mr.profiler.Phase('making issue proxies'):
            issue_views = [
                template_helpers.EZTItem(
                    local_id=issue.local_id,
                    summary=issue.summary,
                    closed=ezt.boolean(issue in closed_issues))
                for issue in issues
            ]

        num_seconds = (int(len(issue_views) * self._SECONDS_PER_UPDATE) +
                       self._SECONDS_OVERHEAD)

        page_perms = self.MakePagePerms(mr, None, permissions.CREATE_ISSUE,
                                        permissions.DELETE_ISSUE)

        return {
            'issue_tab_mode':
            'issueBulkEdit',
            'issues':
            issue_views,
            'local_ids_str':
            ','.join([str(issue.local_id) for issue in issues]),
            'num_issues':
            len(issue_views),
            'show_progress':
            ezt.boolean(num_seconds > self._SLOWNESS_THRESHOLD),
            'num_seconds':
            num_seconds,
            'initial_blocked_on':
            '',
            'initial_blocking':
            '',
            'initial_comment':
            '',
            'initial_status':
            '',
            'initial_owner':
            '',
            'initial_merge_into':
            '',
            'initial_cc':
            '',
            'initial_components':
            '',
            'labels': [],
            'fields':
            field_views,
            'restrict_to_known':
            ezt.boolean(config.restrict_to_known),
            'page_perms':
            page_perms,
            'statuses_offer_merge':
            config.statuses_offer_merge,
            'issue_phase_names':
            list({phase.name.lower()
                  for phase in issue_phases}),
        }
 def testMakeAllFieldValueViews(self):
     labels = [
         'Priority-Low', 'GoodFirstBug', 'Feature-UI', 'Feature-Installer',
         'Launch-Milestone-66'
     ]
     derived_labels = ['OS-Windows', 'OS-Linux']
     self.config.field_defs.append(
         tracker_bizobj.MakeFieldDef(4,
                                     789,
                                     'UIMocks',
                                     tracker_pb2.FieldTypes.URL_TYPE,
                                     'Enhancement',
                                     None,
                                     False,
                                     False,
                                     False,
                                     None,
                                     None,
                                     None,
                                     False,
                                     None,
                                     None,
                                     None,
                                     'no_action',
                                     'descriptive docstring',
                                     False,
                                     approval_id=23,
                                     is_phase_field=False))
     self.config.field_defs.append(
         tracker_bizobj.MakeFieldDef(5,
                                     789,
                                     'LegalFAQs',
                                     tracker_pb2.FieldTypes.URL_TYPE,
                                     'Enhancement',
                                     None,
                                     False,
                                     False,
                                     False,
                                     None,
                                     None,
                                     None,
                                     False,
                                     None,
                                     None,
                                     None,
                                     'no_action',
                                     'descriptive docstring',
                                     False,
                                     approval_id=26,
                                     is_phase_field=False))
     self.config.field_defs.append(
         tracker_bizobj.MakeFieldDef(23,
                                     789,
                                     'Legal',
                                     tracker_pb2.FieldTypes.APPROVAL_TYPE,
                                     'Enhancement',
                                     None,
                                     False,
                                     False,
                                     False,
                                     None,
                                     None,
                                     None,
                                     False,
                                     None,
                                     None,
                                     None,
                                     'no_action',
                                     'descriptive docstring',
                                     False,
                                     approval_id=None,
                                     is_phase_field=False))
     self.config.field_defs.append(
         tracker_bizobj.MakeFieldDef(26,
                                     789,
                                     'UI',
                                     tracker_pb2.FieldTypes.APPROVAL_TYPE,
                                     'Enhancement',
                                     None,
                                     False,
                                     False,
                                     False,
                                     None,
                                     None,
                                     None,
                                     False,
                                     None,
                                     None,
                                     None,
                                     'no_action',
                                     'descriptive docstring',
                                     False,
                                     approval_id=None,
                                     is_phase_field=False))
     self.config.field_defs.append(
         tracker_bizobj.MakeFieldDef(27,
                                     789,
                                     'M-Target',
                                     tracker_pb2.FieldTypes.INT_TYPE,
                                     'Enhancement',
                                     None,
                                     False,
                                     False,
                                     False,
                                     None,
                                     None,
                                     None,
                                     False,
                                     None,
                                     None,
                                     None,
                                     'no_action',
                                     'descriptive docstring',
                                     False,
                                     approval_id=None,
                                     is_phase_field=True))
     field_values = [
         tracker_bizobj.MakeFieldValue(1, 5, None, None, None, None, False),
         tracker_bizobj.MakeFieldValue(27,
                                       74,
                                       None,
                                       None,
                                       None,
                                       None,
                                       False,
                                       phase_id=3),
         # phase_id=4 does not belong to any of the phases given below.
         # this field value should not show up in the views.
         tracker_bizobj.MakeFieldValue(27,
                                       79,
                                       None,
                                       None,
                                       None,
                                       None,
                                       False,
                                       phase_id=4),
     ]
     users_by_id = {}
     phase_1 = tracker_pb2.Phase(phase_id=1, name='Stable')
     phase_2 = tracker_pb2.Phase(phase_id=2, name='Beta')
     phase_3 = tracker_pb2.Phase(phase_id=3, name='stable')
     fvvs = tracker_views.MakeAllFieldValueViews(
         self.config,
         labels,
         derived_labels,
         field_values,
         users_by_id,
         parent_approval_ids=[23],
         phases=[phase_1, phase_2, phase_3])
     self.assertEqual(9, len(fvvs))
     # Values are sorted by (applicable_type, field_name).
     logging.info([fv.field_name for fv in fvvs])
     (estdays_fvv, launch_milestone_fvv, legal_fvv, legal_faq_fvv,
      beta_mtarget_fvv, stable_mtarget_fvv, os_fvv, ui_fvv,
      ui_mocks_fvv) = fvvs
     self.assertEqual('EstDays', estdays_fvv.field_name)
     self.assertEqual(1, len(estdays_fvv.values))
     self.assertEqual(0, len(estdays_fvv.derived_values))
     self.assertEqual('Launch-Milestone', launch_milestone_fvv.field_name)
     self.assertEqual(1, len(launch_milestone_fvv.values))
     self.assertEqual(0, len(launch_milestone_fvv.derived_values))
     self.assertEqual('OS', os_fvv.field_name)
     self.assertEqual(0, len(os_fvv.values))
     self.assertEqual(2, len(os_fvv.derived_values))
     self.assertEqual(ui_mocks_fvv.field_name, 'UIMocks')
     self.assertEqual(ui_mocks_fvv.phase_name, '')
     self.assertTrue(ui_mocks_fvv.applicable)
     self.assertEqual(legal_faq_fvv.field_name, 'LegalFAQs')
     self.assertFalse(legal_faq_fvv.applicable)
     self.assertFalse(legal_fvv.applicable)
     self.assertFalse(ui_fvv.applicable)
     self.assertEqual('M-Target', stable_mtarget_fvv.field_name)
     self.assertEqual('stable', stable_mtarget_fvv.phase_name)
     self.assertEqual(1, len(stable_mtarget_fvv.values))
     self.assertEqual(74, stable_mtarget_fvv.values[0].val)
     self.assertEqual(0, len(stable_mtarget_fvv.derived_values))
     self.assertEqual('M-Target', beta_mtarget_fvv.field_name)
     self.assertEqual('beta', beta_mtarget_fvv.phase_name)
     self.assertEqual(0, len(beta_mtarget_fvv.values))
     self.assertEqual(0, len(beta_mtarget_fvv.values))
Example #6
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 = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
        field_views = tracker_views.MakeAllFieldValueViews(
            config, [], [], [], {})
        approval_subfields_present = any(fv.field_def.is_approval_subfield
                                         for fv in field_views)

        initial_phases = [tracker_pb2.Phase()
                          ] * template_helpers.MAX_NUM_PHASES
        return {
            'admin_tab_mode':
            self._PROCESS_SUBTAB,
            'allow_edit':
            ezt.boolean(True),
            'new_template_form':
            ezt.boolean(True),
            'initial_members_only':
            ezt.boolean(False),
            'template_name':
            '',
            'initial_content':
            '',
            'initial_must_edit_summary':
            ezt.boolean(False),
            'initial_summary':
            '',
            'initial_status':
            '',
            'initial_owner':
            '',
            'initial_owner_defaults_to_member':
            ezt.boolean(False),
            'initial_components':
            '',
            'initial_component_required':
            ezt.boolean(False),
            'initial_admins':
            '',
            'fields': [
                view for view in field_views
                if view.field_def.type_name is not "APPROVAL_TYPE"
            ],
            'initial_add_approvals':
            ezt.boolean(False),
            'initial_phases':
            initial_phases,
            'approvals': [
                view for view in field_views
                if view.field_def.type_name is "APPROVAL_TYPE"
            ],
            'prechecked_approvals': [],
            'required_approval_ids': [],
            'approval_subfields_present':
            ezt.boolean(approval_subfields_present),
            # We do not support setting phase field values during template creation.
            'phase_fields_present':
            ezt.boolean(False),
        }