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
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, }
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()))
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))
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), }