blob: 589afcbc41119adfee42e0920b0a09b957c26456 [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
6from __future__ import print_function
7from __future__ import division
8from __future__ import absolute_import
9
10import logging
11
12from api import monorail_servicer
13from api import converters
14from api.api_proto import common_pb2
15from api.api_proto import features_pb2
16from api.api_proto import features_prpc_pb2
17from businesslogic import work_env
Copybara854996b2021-09-07 19:36:02 +000018from features import features_bizobj
19from framework import exceptions
20from framework import framework_bizobj
21from framework import framework_views
22from framework import paginate
23from framework import permissions
24from services import features_svc
25from tracker import tracker_bizobj
26
27
28class FeaturesServicer(monorail_servicer.MonorailServicer):
29 """Handle API requests related to Features objects.
30
31 Each API request is implemented with a method as defined in the .proto
32 file that does any request-specific validation, uses work_env to
33 safely operate on business objects, and returns a response proto.
34 """
35
36 DESCRIPTION = features_prpc_pb2.FeaturesServiceDescription
37
38 @monorail_servicer.PRPCMethod
39 def ListHotlistsByUser(self, mc, request):
40 """Return the hotlists for the given user."""
41 user_id = converters.IngestUserRef(
42 mc.cnxn, request.user, self.services.user)
43
44 with work_env.WorkEnv(mc, self.services) as we:
45 mc.LookupLoggedInUserPerms(None)
46 hotlists = we.ListHotlistsByUser(user_id)
47
48 with mc.profiler.Phase('making user views'):
49 users_involved = features_bizobj.UsersInvolvedInHotlists(hotlists)
50 users_by_id = framework_views.MakeAllUserViews(
51 mc.cnxn, self.services.user, users_involved)
52 framework_views.RevealAllEmailsToMembers(
53 mc.cnxn, self.services, mc.auth, users_by_id)
54
55 converted_hotlists = [
56 converters.ConvertHotlist(hotlist, users_by_id)
57 for hotlist in hotlists]
58
59 result = features_pb2.ListHotlistsByUserResponse(
60 hotlists=converted_hotlists)
61
62 return result
63
64 @monorail_servicer.PRPCMethod
65 def ListHotlistsByIssue(self, mc, request):
66 # type: (MonorailConnection, proto.features.ListHotlistsByIssueRequest) ->
67 # proto.features.ListHotlistsByIssueResponse
68 """Return the hotlists the given issue is part of."""
69 issue_id = converters.IngestIssueRefs(
70 mc.cnxn, [request.issue], self.services)[0]
71
72 with work_env.WorkEnv(mc, self.services) as we:
73 project = we.GetProjectByName(request.issue.project_name)
74 mc.LookupLoggedInUserPerms(project)
75 hotlists = we.ListHotlistsByIssue(issue_id)
76
77 # Reduce spam by only showing hotlists that belong to a project member.
78 project_hotlists = [
79 hotlist for hotlist in hotlists if framework_bizobj.UserIsInProject(
80 project, set(hotlist.owner_ids + hotlist.editor_ids)) or
81 features_bizobj.UserIsInHotlist(hotlist, mc.auth.effective_ids)
82 ]
83 if project_hotlists and len(hotlists) / len(project_hotlists) > 10:
84 logging.warning(
85 'Unusual hotlist activity in %s:%s' %
86 (request.issue.project_name, issue_id))
87
88 with mc.profiler.Phase('making user views'):
89 users_involved = features_bizobj.UsersInvolvedInHotlists(project_hotlists)
90 users_by_id = framework_views.MakeAllUserViews(
91 mc.cnxn, self.services.user, users_involved)
92 framework_views.RevealAllEmailsToMembers(
93 mc.cnxn, self.services, mc.auth, users_by_id)
94
95 converted_hotlists = [
96 converters.ConvertHotlist(hotlist, users_by_id)
97 for hotlist in project_hotlists
98 ]
99
100 result = features_pb2.ListHotlistsByIssueResponse(
101 hotlists=converted_hotlists)
102
103 return result
104
105 @monorail_servicer.PRPCMethod
106 def ListRecentlyVisitedHotlists(self, mc, _request):
107 """Return the recently visited hotlists for the logged in user."""
108 with work_env.WorkEnv(mc, self.services) as we:
109 mc.LookupLoggedInUserPerms(None)
110 hotlists = we.ListRecentlyVisitedHotlists()
111
112 with mc.profiler.Phase('making user views'):
113 users_involved = features_bizobj.UsersInvolvedInHotlists(hotlists)
114 users_by_id = framework_views.MakeAllUserViews(
115 mc.cnxn, self.services.user, users_involved)
116 framework_views.RevealAllEmailsToMembers(
117 mc.cnxn, self.services, mc.auth, users_by_id)
118
119 converted_hotlists = [
120 converters.ConvertHotlist(hotlist, users_by_id)
121 for hotlist in hotlists]
122
123 result = features_pb2.ListRecentlyVisitedHotlistsResponse(
124 hotlists=converted_hotlists)
125
126 return result
127
128 @monorail_servicer.PRPCMethod
129 def ListStarredHotlists(self, mc, _request):
130 """Return the starred hotlists for the logged in user."""
131 with work_env.WorkEnv(mc, self.services) as we:
132 mc.LookupLoggedInUserPerms(None)
133 hotlists = we.ListStarredHotlists()
134
135 with mc.profiler.Phase('maknig user views'):
136 users_involved = features_bizobj.UsersInvolvedInHotlists(hotlists)
137 users_by_id = framework_views.MakeAllUserViews(
138 mc.cnxn, self.services.user, users_involved)
139 framework_views.RevealAllEmailsToMembers(
140 mc.cnxn, self.services, mc.auth, users_by_id)
141
142 converted_hotlists = [
143 converters.ConvertHotlist(hotlist, users_by_id)
144 for hotlist in hotlists]
145
146 result = features_pb2.ListStarredHotlistsResponse(
147 hotlists=converted_hotlists)
148
149 return result
150
151 @monorail_servicer.PRPCMethod
152 def GetHotlistStarCount(self, mc, request):
153 """Get the star count for the specified hotlist."""
154 hotlist_id = converters.IngestHotlistRef(
155 mc.cnxn, self.services.user, self.services.features,
156 request.hotlist_ref)
157
158 with work_env.WorkEnv(mc, self.services) as we:
159 mc.LookupLoggedInUserPerms(None)
160 star_count = we.GetHotlistStarCount(hotlist_id)
161
162 result = features_pb2.GetHotlistStarCountResponse(star_count=star_count)
163 return result
164
165 @monorail_servicer.PRPCMethod
166 def StarHotlist(self, mc, request):
167 """Star the specified hotlist."""
168 hotlist_id = converters.IngestHotlistRef(
169 mc.cnxn, self.services.user, self.services.features,
170 request.hotlist_ref)
171
172 with work_env.WorkEnv(mc, self.services) as we:
173 mc.LookupLoggedInUserPerms(None)
174 we.StarHotlist(hotlist_id, request.starred)
175 star_count = we.GetHotlistStarCount(hotlist_id)
176
177 result = features_pb2.StarHotlistResponse(star_count=star_count)
178 return result
179
180 @monorail_servicer.PRPCMethod
181 def GetHotlist(self, mc, request):
182 """Get the Hotlist metadata for the specified hotlist."""
183 hotlist_id = converters.IngestHotlistRef(
184 mc.cnxn, self.services.user, self.services.features,
185 request.hotlist_ref)
186
187 with work_env.WorkEnv(mc, self.services) as we:
188 mc.LookupLoggedInUserPerms(None)
189 hotlist = we.GetHotlist(hotlist_id)
190
191 with mc.profiler.Phase('making user views'):
192 users_involved = features_bizobj.UsersInvolvedInHotlists([hotlist])
193 users_by_id = framework_views.MakeAllUserViews(
194 mc.cnxn, self.services.user, users_involved)
195 framework_views.RevealAllEmailsToMembers(
196 mc.cnxn, self.services, mc.auth, users_by_id)
197
198 converted_hotlist = converters.ConvertHotlist(hotlist, users_by_id)
199 return features_pb2.GetHotlistResponse(hotlist=converted_hotlist)
200
201 @monorail_servicer.PRPCMethod
202 def CreateHotlist(self, mc, request):
203 """Create a new hotlist."""
204 editor_ids = converters.IngestUserRefs(
205 mc.cnxn, request.editor_refs, self.services.user)
206 issue_ids = converters.IngestIssueRefs(
207 mc.cnxn, request.issue_refs, self.services)
208
209 with work_env.WorkEnv(mc, self.services) as we:
210 we.CreateHotlist(
211 request.name, request.summary, request.description, editor_ids,
212 issue_ids, request.is_private, '')
213
214 result = features_pb2.CreateHotlistResponse()
215 return result
216
217 @monorail_servicer.PRPCMethod
218 def CheckHotlistName(self, mc, request):
219 """Check that a hotlist name is valid and not already in use."""
220 with work_env.WorkEnv(mc, self.services) as we:
221 error = we.CheckHotlistName(request.name)
222 result = features_pb2.CheckHotlistNameResponse(error=error)
223 return result
224
225 @monorail_servicer.PRPCMethod
226 def RemoveIssuesFromHotlists(self, mc, request):
227 """Remove the given issues from the given hotlists."""
228 hotlist_ids = converters.IngestHotlistRefs(
229 mc.cnxn, self.services.user, self.services.features,
230 request.hotlist_refs)
231 issue_ids = converters.IngestIssueRefs(
232 mc.cnxn, request.issue_refs, self.services)
233
234 with work_env.WorkEnv(mc, self.services) as we:
235 mc.LookupLoggedInUserPerms(None)
236 we.RemoveIssuesFromHotlists(hotlist_ids, issue_ids)
237
238 result = features_pb2.RemoveIssuesFromHotlistsResponse()
239 return result
240
241 @monorail_servicer.PRPCMethod
242 def AddIssuesToHotlists(self, mc, request):
243 """Add the given issues to the given hotlists."""
244 hotlist_ids = converters.IngestHotlistRefs(
245 mc.cnxn, self.services.user, self.services.features,
246 request.hotlist_refs)
247 issue_ids = converters.IngestIssueRefs(
248 mc.cnxn, request.issue_refs, self.services)
249
250 with work_env.WorkEnv(mc, self.services) as we:
251 mc.LookupLoggedInUserPerms(None)
252 we.AddIssuesToHotlists(hotlist_ids, issue_ids, request.note)
253
254 result = features_pb2.AddIssuesToHotlistsResponse()
255 return result
256
257 @monorail_servicer.PRPCMethod
258 def RerankHotlistIssues(self, mc, request):
259 """Rerank issues in the given hotlist."""
260 hotlist_id = converters.IngestHotlistRef(
261 mc.cnxn, self.services.user, self.services.features,
262 request.hotlist_ref)
263 moved_issue_ids = converters.IngestIssueRefs(
264 mc.cnxn, request.moved_refs, self.services)
265 [target_issue_id] = converters.IngestIssueRefs(
266 mc.cnxn, [request.target_ref], self.services)
267
268 with work_env.WorkEnv(mc, self.services) as we:
269 we.RerankHotlistIssues(
270 hotlist_id, moved_issue_ids, target_issue_id, request.split_above)
271
272 # TODO(jojwang): return updated hotlist items.
273 with mc.profiler.Phase('converting to response objects'):
274 result = features_pb2.RerankHotlistIssuesResponse()
275
276 return result
277
278 @monorail_servicer.PRPCMethod
279 def UpdateHotlistIssueNote(self, mc, request):
280 """Update the note for the given issue in the given hotlist."""
281 hotlist_id = converters.IngestHotlistRef(
282 mc.cnxn, self.services.user, self.services.features,
283 request.hotlist_ref)
284 issue_id = converters.IngestIssueRefs(
285 mc.cnxn, [request.issue_ref], self.services)[0]
286
287 with work_env.WorkEnv(mc, self.services) as we:
288 project = we.GetProjectByName(request.issue_ref.project_name)
289 mc.LookupLoggedInUserPerms(project)
290 we.UpdateHotlistIssueNote(hotlist_id, issue_id, request.note)
291
292 result = features_pb2.UpdateHotlistIssueNoteResponse()
293 return result
294
295 @monorail_servicer.PRPCMethod
296 def DeleteHotlist(self, mc, request):
297 """Delete the given hotlist"""
298 hotlist_id = converters.IngestHotlistRef(
299 mc.cnxn, self.services.user, self.services.features,
300 request.hotlist_ref)
301
302 with work_env.WorkEnv(mc, self.services) as we:
303 we.DeleteHotlist(hotlist_id)
304
305 return features_pb2.DeleteHotlistResponse()