blob: 4bda0062599ecc45ac17586b2cfefba103a1fa8e [file] [log] [blame]
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01001# Copyright 2018 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00004
5"""A servlet for project owners to edit/delete a template"""
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
Copybara854996b2021-09-07 19:36:02 +000010import time
11
12import ezt
13
Copybara854996b2021-09-07 19:36:02 +000014from framework import framework_helpers
15from framework import framework_views
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010016from framework import permissions
Copybara854996b2021-09-07 19:36:02 +000017from framework import servlet
18from framework import urls
Copybara854996b2021-09-07 19:36:02 +000019from tracker import field_helpers
20from tracker import template_helpers
21from tracker import tracker_bizobj
Copybara854996b2021-09-07 19:36:02 +000022from tracker import tracker_views
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010023from mrproto import tracker_pb2
Copybara854996b2021-09-07 19:36:02 +000024
25
26class TemplateDetail(servlet.Servlet):
27 """Servlet allowing project owners to edit/delete an issue template"""
28
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010029 _MAIN_TAB_MODE = servlet.Servlet.MAIN_TAB_PROCESS
Copybara854996b2021-09-07 19:36:02 +000030 _PAGE_TEMPLATE = 'tracker/template-detail-page.ezt'
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010031 _PROCESS_SUBTAB = servlet.Servlet.PROCESS_TAB_TEMPLATES
Copybara854996b2021-09-07 19:36:02 +000032
33 def AssertBasePermission(self, mr):
34 """Check whether the user has any permission to visit this page.
35
36 Args:
37 mr: commonly used info parsed from the request.
38 """
39 super(TemplateDetail, self).AssertBasePermission(mr)
40 template = self.services.template.GetTemplateByName(mr.cnxn,
41 mr.template_name, mr.project_id)
42
43 if template:
44 allow_view = permissions.CanViewTemplate(
45 mr.auth.effective_ids, mr.perms, mr.project, template)
46 if not allow_view:
47 raise permissions.PermissionException(
48 'User is not allowed to view this issue template')
49 else:
50 self.abort(404, 'issue template not found %s' % mr.template_name)
51
52 def GatherPageData(self, mr):
53 """Build up a dictionary of data values to use when rendering the page.
54
55 Args:
56 mr: commonly used info parsed from the request.
57
58 Returns:
59 Dict of values used by EZT for rendering the page.
60 """
61
62 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
63 template = self.services.template.GetTemplateByName(mr.cnxn,
64 mr.template_name, mr.project_id)
65 template_view = tracker_views.IssueTemplateView(
66 mr, template, self.services.user, config)
67 with mr.profiler.Phase('making user views'):
68 users_involved = tracker_bizobj.UsersInvolvedInTemplate(template)
69 users_by_id = framework_views.MakeAllUserViews(
70 mr.cnxn, self.services.user, users_involved)
71 framework_views.RevealAllEmailsToMembers(
72 mr.cnxn, self.services, mr.auth, users_by_id, mr.project)
73 field_name_set = {fd.field_name.lower() for fd in config.field_defs
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010074 if fd.field_type == tracker_pb2.FieldTypes.ENUM_TYPE and
Copybara854996b2021-09-07 19:36:02 +000075 not fd.is_deleted}
76 non_masked_labels = tracker_bizobj.NonMaskedLabels(
77 template.labels, field_name_set)
78
79 field_views = tracker_views.MakeAllFieldValueViews(
80 config, template.labels, [], template.field_values, users_by_id,
81 phases=template.phases)
82 uneditable_fields = ezt.boolean(False)
83 for fv in field_views:
84 if permissions.CanEditValueForFieldDef(
85 mr.auth.effective_ids, mr.perms, mr.project, fv.field_def.field_def):
86 fv.is_editable = ezt.boolean(True)
87 else:
88 fv.is_editable = ezt.boolean(False)
89 uneditable_fields = ezt.boolean(True)
90
91 (prechecked_approvals, required_approval_ids,
92 initial_phases) = template_helpers.GatherApprovalsPageData(
93 template.approval_values, template.phases, config)
94
95 allow_edit = permissions.CanEditTemplate(
96 mr.auth.effective_ids, mr.perms, mr.project, template)
97
98 return {
99 'admin_tab_mode':
100 self._PROCESS_SUBTAB,
101 'allow_edit':
102 ezt.boolean(allow_edit),
103 'uneditable_fields':
104 uneditable_fields,
105 'new_template_form':
106 ezt.boolean(False),
107 'initial_members_only':
108 template_view.members_only,
109 'template_name':
110 template_view.name,
111 'initial_summary':
112 template_view.summary,
113 'initial_must_edit_summary':
114 template_view.summary_must_be_edited,
115 'initial_content':
116 template_view.content,
117 'initial_status':
118 template_view.status,
119 'initial_owner':
120 template_view.ownername,
121 'initial_owner_defaults_to_member':
122 template_view.owner_defaults_to_member,
123 'initial_components':
124 template_view.components,
125 'initial_component_required':
126 template_view.component_required,
127 'fields':
128 [
129 view for view in field_views
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100130 if view.field_def.type_name != 'APPROVAL_TYPE'
Copybara854996b2021-09-07 19:36:02 +0000131 ],
132 'initial_add_approvals':
133 ezt.boolean(prechecked_approvals),
134 'initial_phases':
135 initial_phases,
136 'approvals':
137 [
138 view for view in field_views
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100139 if view.field_def.type_name == 'APPROVAL_TYPE'
Copybara854996b2021-09-07 19:36:02 +0000140 ],
141 'prechecked_approvals':
142 prechecked_approvals,
143 'required_approval_ids':
144 required_approval_ids,
145 'labels':
146 non_masked_labels,
147 'initial_admins':
148 template_view.admin_names,
149 }
150
151 def ProcessFormData(self, mr, post_data):
152 """Validate and store the contents of the issues tracker admin page.
153
154 Args:
155 mr: commonly used info parsed from the request.
156 post_data: HTML form data from the request.
157
158 Returns:
159 String URL to redirect the user to, or None if response was already sent.
160 """
161
162 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
163 parsed = template_helpers.ParseTemplateRequest(post_data, config)
164 field_helpers.ShiftEnumFieldsIntoLabels(
165 parsed.labels, [], parsed.field_val_strs, [], config)
166 template = self.services.template.GetTemplateByName(mr.cnxn,
167 parsed.name, mr.project_id)
168 allow_edit = permissions.CanEditTemplate(
169 mr.auth.effective_ids, mr.perms, mr.project, template)
170 if not allow_edit:
171 raise permissions.PermissionException(
172 'User is not allowed edit this issue template.')
173
174 if 'deletetemplate' in post_data:
175 self.services.template.DeleteIssueTemplateDef(
176 mr.cnxn, mr.project_id, template.template_id)
177 return framework_helpers.FormatAbsoluteURL(
178 mr, urls.ADMIN_TEMPLATES, deleted=1, ts=int(time.time()))
179
180 (admin_ids, owner_id, component_ids,
181 field_values, phases,
182 approvals) = template_helpers.GetTemplateInfoFromParsed(
183 mr, self.services, parsed, config)
184
185 labels = [label for label in parsed.labels if label]
186 field_helpers.AssertCustomFieldsEditPerms(
187 mr, config, field_values, [], [], labels, [])
188 field_helpers.ApplyRestrictedDefaultValues(
189 mr, config, field_values, labels, template.field_values,
190 template.labels)
191
192 if mr.errors.AnyErrors():
193 field_views = tracker_views.MakeAllFieldValueViews(
194 config, [], [], field_values, {})
195
196 prechecked_approvals = template_helpers.GetCheckedApprovalsFromParsed(
197 parsed.approvals_to_phase_idx)
198
199 self.PleaseCorrect(
200 mr,
201 initial_members_only=ezt.boolean(parsed.members_only),
202 template_name=parsed.name,
203 initial_summary=parsed.summary,
204 initial_must_edit_summary=ezt.boolean(parsed.summary_must_be_edited),
205 initial_content=parsed.content,
206 initial_status=parsed.status,
207 initial_owner=parsed.owner_str,
208 initial_owner_defaults_to_member=ezt.boolean(
209 parsed.owner_defaults_to_member),
210 initial_components=', '.join(parsed.component_paths),
211 initial_component_required=ezt.boolean(parsed.component_required),
212 initial_admins=parsed.admin_str,
213 labels=parsed.labels,
214 fields=[view for view in field_views
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100215 if view.field_def.type_name != 'APPROVAL_TYPE'],
Copybara854996b2021-09-07 19:36:02 +0000216 initial_add_approvals=ezt.boolean(parsed.add_approvals),
217 initial_phases=[tracker_pb2.Phase(name=name) for name in
218 parsed.phase_names],
219 approvals=[view for view in field_views
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100220 if view.field_def.type_name == 'APPROVAL_TYPE'],
Copybara854996b2021-09-07 19:36:02 +0000221 prechecked_approvals=prechecked_approvals,
222 required_approval_ids=parsed.required_approval_ids
223 )
224 return
225
226 self.services.template.UpdateIssueTemplateDef(
227 mr.cnxn, mr.project_id, template.template_id, name=parsed.name,
228 content=parsed.content, summary=parsed.summary,
229 summary_must_be_edited=parsed.summary_must_be_edited,
230 status=parsed.status, members_only=parsed.members_only,
231 owner_defaults_to_member=parsed.owner_defaults_to_member,
232 component_required=parsed.component_required, owner_id=owner_id,
233 labels=labels, component_ids=component_ids, admin_ids=admin_ids,
234 field_values=field_values, phases=phases, approval_values=approvals)
235
236 return framework_helpers.FormatAbsoluteURL(
237 mr, urls.TEMPLATE_DETAIL, template=template.name,
238 saved=1, ts=int(time.time()))
Adrià Vilanova Martínezde942802022-07-15 14:06:55 +0200239
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100240 def GetTemplateDetail(self, **kwargs):
241 return self.handler(**kwargs)
Adrià Vilanova Martínezde942802022-07-15 14:06:55 +0200242
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100243 def PostTemplateDetail(self, **kwargs):
244 return self.handler(**kwargs)