Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: appengine/monorail/tracker/fieldcreate.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « appengine/monorail/tracker/field_helpers.py ('k') | appengine/monorail/tracker/fielddetail.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is govered 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 field def."""
7
8 import logging
9 import re
10 import time
11
12 from third_party import ezt
13
14 from framework import framework_helpers
15 from framework import jsonfeed
16 from framework import permissions
17 from framework import servlet
18 from framework import urls
19 from tracker import field_helpers
20 from tracker import tracker_constants
21 from tracker import tracker_helpers
22
23
24 class FieldCreate(servlet.Servlet):
25 """Servlet allowing project owners to create a custom field."""
26
27 _MAIN_TAB_MODE = servlet.Servlet.MAIN_TAB_PROCESS
28 _PAGE_TEMPLATE = 'tracker/field-create-page.ezt'
29
30 def AssertBasePermission(self, mr):
31 """Check whether the user has any permission to visit this page.
32
33 Args:
34 mr: commonly used info parsed from the request.
35 """
36 super(FieldCreate, self).AssertBasePermission(mr)
37 if not self.CheckPerm(mr, permissions.EDIT_PROJECT):
38 raise permissions.PermissionException(
39 'You are not allowed to administer this project')
40
41 def GatherPageData(self, mr):
42 """Build up a dictionary of data values to use when rendering the page.
43
44 Args:
45 mr: commonly used info parsed from the request.
46
47 Returns:
48 Dict of values used by EZT for rendering the page.
49 """
50 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
51 well_known_issue_types = tracker_helpers.FilterIssueTypes(config)
52
53 return {
54 'admin_tab_mode': servlet.Servlet.PROCESS_TAB_LABELS,
55 'initial_field_name': '',
56 'initial_field_docstring': '',
57 'initial_is_required': ezt.boolean(False),
58 'initial_is_multivalued': ezt.boolean(False),
59 'initial_choices': '',
60 'initial_admins': '',
61 'initial_type': 'enum_type',
62 'initial_applicable_type': '', # That means any issue type
63 'initial_applicable_predicate': '',
64 'initial_needs_member': ezt.boolean(False),
65 'initial_needs_perm': '',
66 'initial_grants_perm': '',
67 'initial_notify_on': 0,
68 'well_known_issue_types': well_known_issue_types,
69 }
70
71 def ProcessFormData(self, mr, post_data):
72 """Validate and store the contents of the issues tracker admin page.
73
74 Args:
75 mr: commonly used info parsed from the request.
76 post_data: HTML form data from the request.
77
78 Returns:
79 String URL to redirect the user to, or None if response was already sent.
80 """
81 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
82 parsed = field_helpers.ParseFieldDefRequest(post_data, config)
83
84 if not tracker_constants.FIELD_NAME_RE.match(parsed.field_name):
85 mr.errors.field_name = 'Invalid field name'
86
87 field_name_error_msg = FieldNameErrorMessage(parsed.field_name, config)
88 if field_name_error_msg:
89 mr.errors.field_name = field_name_error_msg
90
91 if (parsed.min_value is not None and parsed.max_value is not None and
92 parsed.min_value > parsed.max_value):
93 mr.errors.min_value = 'Minimum value must be less than maximum.'
94
95 if parsed.regex:
96 try:
97 re.compile(parsed.regex)
98 except re.error:
99 mr.errors.regex = 'Invalid regular expression.'
100
101 admin_ids, admin_str = tracker_helpers.ParseAdminUsers(
102 mr.cnxn, post_data['admin_names'], self.services.user)
103
104 if mr.errors.AnyErrors():
105 self.PleaseCorrect(
106 mr, initial_field_name=parsed.field_name,
107 initial_type=parsed.field_type_str,
108 initial_field_docstring=parsed.field_docstring,
109 initial_applicable_type=parsed.applicable_type,
110 initial_applicable_predicate=parsed.applicable_predicate,
111 initial_needs_member=ezt.boolean(parsed.needs_member),
112 initial_needs_perm=parsed.needs_perm,
113 initial_is_required=ezt.boolean(parsed.is_required),
114 initial_is_multivalued=ezt.boolean(parsed.is_multivalued),
115 initial_grants_perm=parsed.grants_perm,
116 initial_notify_on=parsed.notify_on,
117 initial_choices=parsed.choices_text,
118 initial_admins=admin_str)
119 return
120
121 self.services.config.CreateFieldDef(
122 mr.cnxn, mr.project_id, parsed.field_name, parsed.field_type_str,
123 parsed.applicable_type, parsed.applicable_predicate,
124 parsed.is_required, parsed.is_multivalued,
125 parsed.min_value, parsed.max_value, parsed.regex, parsed.needs_member,
126 parsed.needs_perm, parsed.grants_perm, parsed.notify_on,
127 parsed.field_docstring, admin_ids)
128 if parsed.field_type_str == 'enum_type':
129 self.services.config.UpdateConfig(
130 mr.cnxn, mr.project, well_known_labels=parsed.revised_labels)
131
132 return framework_helpers.FormatAbsoluteURL(
133 mr, urls.ADMIN_LABELS, saved=1, ts=int(time.time()))
134
135
136 class CheckFieldNameJSON(jsonfeed.JsonFeed):
137 """JSON data for handling name checks when creating a field."""
138
139 def HandleRequest(self, mr):
140 """Provide the UI with info about the availability of the field name.
141
142 Args:
143 mr: common information parsed from the HTTP request.
144
145 Returns:
146 Results dictionary in JSON format.
147 """
148 field_name = mr.GetParam('field')
149 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
150 choices = ExistingEnumChoices(field_name, config)
151 choices_dicts = [dict(name=choice.name_padded, doc=choice.docstring)
152 for choice in choices]
153 message = FieldNameErrorMessage(field_name, config)
154
155 return {
156 'error_message': message,
157 'choices': choices_dicts,
158 }
159
160
161 def FieldNameErrorMessage(field_name, config):
162 """Return an error message for the given field name, or None."""
163 field_name_lower = field_name.lower()
164 if field_name_lower in tracker_constants.RESERVED_PREFIXES:
165 return 'That name is reserved.'
166
167 for fd in config.field_defs:
168 fn_lower = fd.field_name.lower()
169 if field_name_lower == fn_lower:
170 return 'That name is already in use.'
171 if field_name_lower.startswith(fn_lower + '-'):
172 return 'An existing field name is a prefix of that name.'
173 if fn_lower.startswith(field_name_lower + '-'):
174 return 'That name is a prefix of an existing field name.'
175
176 return None
177
178
179 def ExistingEnumChoices(field_name, config):
180 """Return a list of existing label choices for the given prefix."""
181 # If there are existing labels with that prefix, then it must be enum.
182 # The existing labels will be treated as field values.
183 choices = tracker_helpers.LabelsMaskedByFields(
184 config, [field_name], trim_prefix=True)
185 return choices
OLDNEW
« no previous file with comments | « appengine/monorail/tracker/field_helpers.py ('k') | appengine/monorail/tracker/fielddetail.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698