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

Side by Side Diff: appengine/monorail/tracker/issueoptions.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/issuelistcsv.py ('k') | appengine/monorail/tracker/issueoriginal.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 """JSON feed for issue autocomplete options."""
7
8 import logging
9 from third_party import ezt
10
11 from framework import framework_helpers
12 from framework import framework_views
13 from framework import jsonfeed
14 from framework import monorailrequest
15 from framework import permissions
16 from project import project_helpers
17 from tracker import tracker_helpers
18 from tracker import tracker_views
19
20
21 # Here are some restriction labels to help people do the most common things
22 # that they might want to do with restrictions.
23 _FREQUENT_ISSUE_RESTRICTIONS = [
24 (permissions.VIEW, permissions.EDIT_ISSUE,
25 'Only users who can edit the issue may access it'),
26 (permissions.ADD_ISSUE_COMMENT, permissions.EDIT_ISSUE,
27 'Only users who can edit the issue may add comments'),
28 ]
29
30
31 # These issue restrictions should be offered as examples whenever the project
32 # does not have any custom permissions in use already.
33 _EXAMPLE_ISSUE_RESTRICTIONS = [
34 (permissions.VIEW, 'CoreTeam',
35 'Custom permission CoreTeam is needed to access'),
36 ]
37
38
39 class IssueOptionsJSON(jsonfeed.JsonFeed):
40 """JSON data describing all issue statuses, labels, and members."""
41
42 def HandleRequest(self, mr):
43 """Provide the UI with info used in auto-completion.
44
45 Args:
46 mr: common information parsed from the HTTP request.
47
48 Returns:
49 Results dictionary in JSON format
50 """
51 # Issue options data can be cached separately in each user's browser. When
52 # the project changes, a new cached_content_timestamp is set and it will
53 # cause new requests to use a new URL.
54 self.SetCacheHeaders(self.response)
55
56 member_data = project_helpers.BuildProjectMembers(
57 mr.cnxn, mr.project, self.services.user)
58 owner_views = member_data['owners']
59 committer_views = member_data['committers']
60 contributor_views = member_data['contributors']
61
62 config = self.services.config.GetProjectConfig(mr.cnxn, mr.project_id)
63
64 open_statuses = []
65 closed_statuses = []
66 for wks in config.well_known_statuses:
67 if not wks.deprecated:
68 item = dict(name=wks.status, doc=wks.status_docstring)
69 if wks.means_open:
70 open_statuses.append(item)
71 else:
72 closed_statuses.append(item)
73
74 # TODO(jrobbins): restrictions on component definitions?
75 components = [{'name': cd.path, 'doc': cd.docstring}
76 for cd in config.component_defs if not cd.deprecated]
77
78 labels = []
79 field_names = [
80 fd.field_name for fd in config.field_defs if not fd.is_deleted]
81 non_masked_labels = tracker_helpers.LabelsNotMaskedByFields(
82 config, field_names)
83 for wkl in non_masked_labels:
84 if not wkl.commented:
85 item = dict(name=wkl.name, doc=wkl.docstring)
86 labels.append(item)
87
88 # TODO(jrobbins): omit fields that they don't have permission to view.
89 field_def_views = [
90 tracker_views.FieldDefView(fd, config)
91 for fd in config.field_defs
92 if not fd.is_deleted]
93 fields = [
94 dict(field_name=fdv.field_name, field_type=fdv.field_type,
95 field_id=fdv.field_id, needs_perm=fdv.needs_perm,
96 is_required=fdv.is_required, is_multivalued=fdv.is_multivalued,
97 choices=[dict(name=c.name, doc=c.docstring) for c in fdv.choices],
98 docstring=fdv.docstring)
99 for fdv in field_def_views]
100
101 frequent_restrictions = _FREQUENT_ISSUE_RESTRICTIONS[:]
102 custom_permissions = permissions.GetCustomPermissions(mr.project)
103 if not custom_permissions:
104 frequent_restrictions.extend(
105 _EXAMPLE_ISSUE_RESTRICTIONS)
106
107 labels.extend(_BuildRestrictionChoices(
108 mr.project, frequent_restrictions,
109 permissions.STANDARD_ISSUE_PERMISSIONS))
110
111 group_ids = self.services.usergroup.DetermineWhichUserIDsAreGroups(
112 mr.cnxn, [mem.user_id for mem in member_data['all_members']])
113 logging.info('group_ids is %r', group_ids)
114
115 # TODO(jrobbins): Normally, users will be allowed view the members
116 # of any user group if the project From: email address is listed
117 # as a group member, as well as any group that they are personally
118 # members of.
119 member_ids, owner_ids = self.services.usergroup.LookupVisibleMembers(
120 mr.cnxn, group_ids, mr.perms, mr.auth.effective_ids, self.services)
121 indirect_ids = set()
122 for gid in group_ids:
123 indirect_ids.update(member_ids.get(gid, []))
124 indirect_ids.update(owner_ids.get(gid, []))
125 indirect_user_ids = list(indirect_ids)
126 indirect_member_views = framework_views.MakeAllUserViews(
127 mr.cnxn, self.services.user, indirect_user_ids).values()
128
129 visible_member_views = _FilterMemberData(
130 mr, owner_views, committer_views, contributor_views,
131 indirect_member_views)
132 # Filter out servbice accounts
133 visible_member_views = [m for m in visible_member_views
134 if not framework_helpers.IsServiceAccount(m.email)]
135 visible_member_email_list = list({
136 uv.email for uv in visible_member_views})
137 user_indexes = {email: idx
138 for idx, email in enumerate(visible_member_email_list)}
139 visible_members_dict = {}
140 for uv in visible_member_views:
141 visible_members_dict[uv.email] = uv.user_id
142 group_ids = self.services.usergroup.DetermineWhichUserIDsAreGroups(
143 mr.cnxn, visible_members_dict.values())
144
145 for field_dict in fields:
146 needed_perm = field_dict['needs_perm']
147 if needed_perm:
148 qualified_user_indexes = []
149 for uv in visible_member_views:
150 # TODO(jrobbins): Similar code occurs in field_helpers.py.
151 user = self.services.user.GetUser(mr.cnxn, uv.user_id)
152 auth = monorailrequest.AuthData.FromUserID(
153 mr.cnxn, uv.user_id, self.services)
154 user_perms = permissions.GetPermissions(
155 user, auth.effective_ids, mr.project)
156 has_perm = user_perms.CanUsePerm(
157 needed_perm, auth.effective_ids, mr.project, [])
158 if has_perm:
159 qualified_user_indexes.append(user_indexes[uv.email])
160
161 field_dict['user_indexes'] = sorted(set(qualified_user_indexes))
162
163 excl_prefixes = [prefix.lower() for prefix in
164 config.exclusive_label_prefixes]
165 members_def_list = [dict(name=email, doc='')
166 for email in visible_member_email_list]
167 members_def_list = sorted(
168 members_def_list, key=lambda md: md['name'])
169 for md in members_def_list:
170 md_id = visible_members_dict[md['name']]
171 if md_id in group_ids:
172 md['is_group'] = True
173
174 return {
175 'open': open_statuses,
176 'closed': closed_statuses,
177 'statuses_offer_merge': config.statuses_offer_merge,
178 'components': components,
179 'labels': labels,
180 'fields': fields,
181 'excl_prefixes': excl_prefixes,
182 'strict': ezt.boolean(config.restrict_to_known),
183 'members': members_def_list,
184 'custom_permissions': custom_permissions,
185 }
186
187
188 def _FilterMemberData(
189 mr, owner_views, committer_views, contributor_views,
190 indirect_member_views):
191 """Return a filtered list of members that the user can view.
192
193 In most projects, everyone can view the entire member list. But,
194 some projects are configured to only allow project owners to see
195 all members. In those projects, committers and contributors do not
196 see any contributors. Regardless of how the project is configured
197 or the role that the user plays in the current project, we include
198 any indirect members through user groups that the user has access
199 to view.
200
201 Args:
202 mr: Commonly used info parsed from the HTTP request.
203 owner_views: list of UserViews for project owners.
204 committer_views: list of UserViews for project committers.
205 contributor_views: list of UserViews for project contributors.
206 indirect_member_views: list of UserViews for users who have
207 an indirect role in the project via a user group, and that the
208 logged in user is allowed to see.
209
210 Returns:
211 A list of owners, committer and visible indirect members if the user is not
212 signed in. If the project is set to display contributors to non-owners or
213 the signed in user has necessary permissions then additionally a list of
214 contributors.
215 """
216 visible_members = []
217
218 # Everyone can view owners and committers
219 visible_members.extend(owner_views)
220 visible_members.extend(committer_views)
221
222 # The list of indirect members is already limited to ones that the user
223 # is allowed to see according to user group settings.
224 visible_members.extend(indirect_member_views)
225
226 # If the user is allowed to view the list of contributors, add those too.
227 if permissions.CanViewContributorList(mr):
228 visible_members.extend(contributor_views)
229
230 return visible_members
231
232
233 def _BuildRestrictionChoices(project, freq_restrictions, actions):
234 """Return a list of autocompletion choices for restriction labels.
235
236 Args:
237 project: Project PB for the current project.
238 freq_restrictions: list of (action, perm, doc) tuples for restrictions
239 that are frequently used.
240 actions: list of strings for actions that are relevant to the current
241 artifact.
242
243 Returns:
244 A list of dictionaries [{'name': 'perm name', 'doc': 'docstring'}, ...]
245 suitable for use in a JSON feed to our JS autocompletion functions.
246 """
247 custom_permissions = permissions.GetCustomPermissions(project)
248 choices = []
249
250 for action, perm, doc in freq_restrictions:
251 choices.append({
252 'name': 'Restrict-%s-%s' % (action, perm),
253 'doc': doc,
254 })
255
256 for action in actions:
257 for perm in custom_permissions:
258 choices.append({
259 'name': 'Restrict-%s-%s' % (action, perm),
260 'doc': 'Permission %s needed to use %s' % (perm, action),
261 })
262
263 return choices
OLDNEW
« no previous file with comments | « appengine/monorail/tracker/issuelistcsv.py ('k') | appengine/monorail/tracker/issueoriginal.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698