blob: e10a25b48ff920e2a4ab2874e436ebb11a335dce [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2018 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file or at
4# https://developers.google.com/open-source/licenses/bsd
5
6"""A servlet for project owners to create a new template"""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import collections
12import logging
13import time
14
15import ezt
16
17from framework import authdata
18from framework import framework_bizobj
19from framework import framework_helpers
20from framework import servlet
21from framework import urls
22from framework import permissions
23from tracker import field_helpers
24from tracker import template_helpers
25from tracker import tracker_bizobj
26from tracker import tracker_helpers
27from tracker import tracker_views
28from services import user_svc
29from proto import tracker_pb2
30
31
32class TemplateCreate(servlet.Servlet):
33 """Servlet allowing project owners to create an issue template."""
34
35 _MAIN_TAB_MODE = servlet.Servlet.MAIN_TAB_PROCESS
36 _PAGE_TEMPLATE = 'tracker/template-detail-page.ezt'
37 _PROCESS_SUBTAB = servlet.Servlet.PROCESS_TAB_TEMPLATES
38
39 def AssertBasePermission(self, mr):
40 """Check whether the user has any permission to visit this page.
41
42 Args:
43 mr: commonly used info parsed from the request
44 """
45 super(TemplateCreate, self).AssertBasePermission(mr)
46 if not self.CheckPerm(mr, permissions.EDIT_PROJECT):
47 raise permissions.PermissionException(
48 'User is not allowed to administer this project')
49
50 def GatherPageData(self, mr):
51 """Build up a dictionary of data values to use when rendering the page.
52
53 Args:
54 mr: commonly used info parsed from the request.
55
56 Returns:
57 Dict of values used by EZT for rendering the page.
58 """
59
60 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
61 field_views = tracker_views.MakeAllFieldValueViews(
62 config, [], [], [], {})
63 approval_subfields_present = any(
64 fv.field_def.is_approval_subfield for fv in field_views)
65
66 initial_phases = [tracker_pb2.Phase()] * template_helpers.MAX_NUM_PHASES
67 return {
68 'admin_tab_mode':
69 self._PROCESS_SUBTAB,
70 'allow_edit':
71 ezt.boolean(True),
72 'uneditable_fields':
73 ezt.boolean(False),
74 'new_template_form':
75 ezt.boolean(True),
76 'initial_members_only':
77 ezt.boolean(False),
78 'template_name':
79 '',
80 'initial_content':
81 '',
82 'initial_must_edit_summary':
83 ezt.boolean(False),
84 'initial_summary':
85 '',
86 'initial_status':
87 '',
88 'initial_owner':
89 '',
90 'initial_owner_defaults_to_member':
91 ezt.boolean(False),
92 'initial_components':
93 '',
94 'initial_component_required':
95 ezt.boolean(False),
96 'initial_admins':
97 '',
98 'fields':
99 [
100 view for view in field_views
101 if view.field_def.type_name is not "APPROVAL_TYPE"
102 ],
103 'initial_add_approvals':
104 ezt.boolean(False),
105 'initial_phases':
106 initial_phases,
107 'approvals':
108 [
109 view for view in field_views
110 if view.field_def.type_name is "APPROVAL_TYPE"
111 ],
112 'prechecked_approvals': [],
113 'required_approval_ids': [],
114 'approval_subfields_present':
115 ezt.boolean(approval_subfields_present),
116 # We do not support setting phase field values during template creation.
117 'phase_fields_present':
118 ezt.boolean(False),
119 }
120
121 def ProcessFormData(self, mr, post_data):
122 """Validate and store the contents of the issues tracker admin page.
123
124 Args:
125 mr: commonly used info parsed from the request.
126 post_data: HTML form data from the request.
127
128 Returns:
129 String URL to redirect the user to, or None if response was already sent.
130 """
131
132 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
133 parsed = template_helpers.ParseTemplateRequest(post_data, config)
134 field_helpers.ShiftEnumFieldsIntoLabels(
135 parsed.labels, [], parsed.field_val_strs, [], config)
136
137 if not parsed.name:
138 mr.errors.name = 'Please provide a template name'
139 if self.services.template.GetTemplateByName(mr.cnxn, parsed.name,
140 mr.project_id):
141 mr.errors.name = 'Template with name %s already exists' % parsed.name
142
143 (admin_ids, owner_id, component_ids,
144 field_values, phases,
145 approvals) = template_helpers.GetTemplateInfoFromParsed(
146 mr, self.services, parsed, config)
147
148 labels = [label for label in parsed.labels if label]
149 field_helpers.AssertCustomFieldsEditPerms(
150 mr, config, field_values, [], [], labels, [])
151
152 if mr.errors.AnyErrors():
153 field_views = tracker_views.MakeAllFieldValueViews(
154 config, [], [], field_values, {})
155 prechecked_approvals = template_helpers.GetCheckedApprovalsFromParsed(
156 parsed.approvals_to_phase_idx)
157
158 self.PleaseCorrect(
159 mr,
160 initial_members_only=ezt.boolean(parsed.members_only),
161 template_name=parsed.name,
162 initial_content=parsed.summary,
163 initial_must_edit_summary=ezt.boolean(parsed.summary_must_be_edited),
164 initial_description=parsed.content,
165 initial_status=parsed.status,
166 initial_owner=parsed.owner_str,
167 initial_owner_defaults_to_member=ezt.boolean(
168 parsed.owner_defaults_to_member),
169 initial_components=', '.join(parsed.component_paths),
170 initial_component_required=ezt.boolean(parsed.component_required),
171 initial_admins=parsed.admin_str,
172 labels=parsed.labels,
173 fields=[view for view in field_views
174 if view.field_def.type_name is not 'APPROVAL_TYPE'],
175 initial_add_approvals=ezt.boolean(parsed.add_approvals),
176 initial_phases=[tracker_pb2.Phase(name=name) for name in
177 parsed.phase_names],
178 approvals=[view for view in field_views
179 if view.field_def.type_name is 'APPROVAL_TYPE'],
180 prechecked_approvals=prechecked_approvals,
181 required_approval_ids=parsed.required_approval_ids
182 )
183 return
184
185 self.services.template.CreateIssueTemplateDef(
186 mr.cnxn, mr.project_id, parsed.name, parsed.content, parsed.summary,
187 parsed.summary_must_be_edited, parsed.status, parsed.members_only,
188 parsed.owner_defaults_to_member, parsed.component_required,
189 owner_id, labels, component_ids, admin_ids, field_values, phases=phases,
190 approval_values=approvals)
191
192 return framework_helpers.FormatAbsoluteURL(
193 mr, urls.ADMIN_TEMPLATES, saved=1, ts=int(time.time()))