blob: 2ea2a319b31fc1eede463118f1b6beedc46ffa8f [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2020 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
10from google.protobuf import empty_pb2
11
12from api import resource_name_converters as rnc
13from api.v3 import monorail_servicer
14from api.v3.api_proto import feature_objects_pb2
15from api.v3.api_proto import hotlists_pb2
16from api.v3.api_proto import hotlists_prpc_pb2
17from businesslogic import work_env
18from framework import exceptions
19from features import features_constants
20from tracker import tracker_constants
21
22
23class HotlistsServicer(monorail_servicer.MonorailServicer):
24 """Handle API requests related to Hotlist objects.
25 Each API request is implemented with a method as defined in the
26 .proto file. Each method does any request-specific validation, uses work_env
27 to safely operate on business objects, and returns a response proto.
28 """
29 # NOTE(crbug/monorail/7614): Until the referenced cleanup is complete,
30 # all servicer methods that are scoped to a single Project need to call
31 # mc.LookupLoggedInUserPerms.
32 # Methods in this file do not because hotlists can span projects.
33
34 DESCRIPTION = hotlists_prpc_pb2.HotlistsServiceDescription
35
36 @monorail_servicer.PRPCMethod
37 def ListHotlistItems(self, mc, request):
38 # type: (MonorailContext, ListHotlistItemsRequest) ->
39 # ListHotlistItemsResponse
40 """pRPC API method that implements ListHotlistItems.
41
42 Raises:
43 NoSuchHotlistException if the hotlist is not found.
44 PermissionException if the user is not allowed to view the hotlist.
45 InputException if the request.page_token is invalid, the request does
46 not match the previous request that provided the given page_token, or
47 the page_size is a negative value.
48 """
49 hotlist_id = rnc.IngestHotlistName(request.parent)
50 if request.page_size < 0:
51 raise exceptions.InputException('`page_size` cannot be negative.')
52 page_size = request.page_size
53 if (not request.page_size or
54 request.page_size > features_constants.DEFAULT_RESULTS_PER_PAGE):
55 page_size = features_constants.DEFAULT_RESULTS_PER_PAGE
56
57 # TODO(crbug/monorail/7104): take start from request.page_token
58 start = 0
59 sort_spec = request.order_by.replace(',', ' ')
60
61 with work_env.WorkEnv(mc, self.services) as we:
62 list_result = we.ListHotlistItems(
63 hotlist_id, page_size, start,
64 tracker_constants.ALL_ISSUES_CAN, sort_spec, '')
65
66 # TODO(crbug/monorail/7104): plug in next_page_token when it's been
67 # implemented.
68 next_page_token = ''
69 return hotlists_pb2.ListHotlistItemsResponse(
70 items=self.converter.ConvertHotlistItems(hotlist_id, list_result.items),
71 next_page_token=next_page_token)
72
73
74 @monorail_servicer.PRPCMethod
75 def RerankHotlistItems(self, mc, request):
76 # type: (MonorailContext, RerankHotlistItemsRequest) -> Empty
77 """pRPC API method that implements RerankHotlistItems.
78
79 Raises:
80 NoSuchHotlistException if the hotlist is not found.
81 PermissionException if the user is not allowed to rerank the hotlist.
82 InputException if request.target_position is invalid or
83 request.hotlist_items is empty or contains invalid items.
84 NoSuchIssueException if hotlist item does not exist.
85 """
86
87 hotlist_id = rnc.IngestHotlistName(request.name)
88 moved_issue_ids = rnc.IngestHotlistItemNames(
89 mc.cnxn, request.hotlist_items, self.services)
90
91 with work_env.WorkEnv(mc, self.services) as we:
92 we.RerankHotlistItems(
93 hotlist_id, moved_issue_ids, request.target_position)
94
95 return empty_pb2.Empty()
96
97
98 @monorail_servicer.PRPCMethod
99 def RemoveHotlistItems(self, mc, request):
100 # type: (MonorailContext, RemoveHotlistItemsRequest) -> Empty
101 """pPRC API method that implements RemoveHotlistItems.
102
103 Raises:
104 NoSuchHotlistException if the hotlist is not found.
105 PermissionException if the user is not allowed to edit the hotlist.
106 InputException if the items to be removed are not found in the hotlist.
107 """
108
109 hotlist_id = rnc.IngestHotlistName(request.parent)
110 remove_issue_ids = rnc.IngestIssueNames(
111 mc.cnxn, request.issues, self.services)
112
113 with work_env.WorkEnv(mc, self.services) as we:
114 we.RemoveHotlistItems(hotlist_id, remove_issue_ids)
115
116 return empty_pb2.Empty()
117
118
119 @monorail_servicer.PRPCMethod
120 def AddHotlistItems(self, mc, request):
121 # type: (MonorailContext, AddHotlistItemsRequest) -> Empty
122 """pRPC API method that implements AddHotlistItems.
123
124 Raises:
125 NoSuchHotlistException if the hotlist is not found.
126 PermissionException if the user is not allowed to edit the hotlist.
127 InputException if the request.target_position is invalid or the given
128 list of issues to add is empty or invalid.
129 """
130 hotlist_id = rnc.IngestHotlistName(request.parent)
131 new_issue_ids = rnc.IngestIssueNames(mc.cnxn, request.issues, self.services)
132
133 with work_env.WorkEnv(mc, self.services) as we:
134 we.AddHotlistItems(hotlist_id, new_issue_ids, request.target_position)
135
136 return empty_pb2.Empty()
137
138
139 @monorail_servicer.PRPCMethod
140 def RemoveHotlistEditors(self, mc, request):
141 # type: (MonorailContext, RemoveHotlistEditorsRequest) -> Empty
142 """pPRC API method that implements RemoveHotlistEditors.
143
144 Raises:
145 NoSuchHotlistException if the hotlist is not found.
146 PermissionException if the user is not allowed to edit the hotlist.
147 InputException if the editors to be removed are not found in the hotlist.
148 """
149
150 hotlist_id = rnc.IngestHotlistName(request.name)
151 remove_user_ids = rnc.IngestUserNames(
152 mc.cnxn, request.editors, self.services)
153
154 with work_env.WorkEnv(mc, self.services) as we:
155 we.RemoveHotlistEditors(hotlist_id, remove_user_ids)
156
157 return empty_pb2.Empty()
158
159
160 @monorail_servicer.PRPCMethod
161 def GetHotlist(self, mc, request):
162 # type: (MonorailContext, GetHotlistRequest) -> Hotlist
163 """pRPC API method that implements GetHotlist.
164
165 Raises:
166 InputException if the given name does not have a valid format.
167 NoSuchHotlistException if the hotlist is not found.
168 PermissionException if the user is not allowed to view the hotlist.
169 """
170
171 hotlist_id = rnc.IngestHotlistName(request.name)
172
173 with work_env.WorkEnv(mc, self.services) as we:
174 hotlist = we.GetHotlist(hotlist_id)
175
176 return self.converter.ConvertHotlist(hotlist)
177
178 @monorail_servicer.PRPCMethod
179 def GatherHotlistsForUser(self, mc, request):
180 # type: (MonorailContext, GatherHotlistsForUserRequest)
181 # -> GatherHotlistsForUserResponse
182 """pRPC API method that implements GatherHotlistsForUser.
183
184 Raises:
185 NoSuchUserException if the user is not found.
186 InputException if some request parameters are invalid.
187 """
188
189 user_id = rnc.IngestUserName(mc.cnxn, request.user, self.services)
190
191 with work_env.WorkEnv(mc, self.services) as we:
192 hotlists = we.ListHotlistsByUser(user_id)
193
194 return hotlists_pb2.GatherHotlistsForUserResponse(
195 hotlists=self.converter.ConvertHotlists(hotlists))
196
197 @monorail_servicer.PRPCMethod
198 def UpdateHotlist(self, mc, request):
199 # type: (MonorailContext, UpdateHotlistRequest) -> UpdateHotlistResponse
200 """pRPC API method that implements UpdateHotlist.
201
202 Raises:
203 NoSuchHotlistException if the hotlist is not found.
204 PermissionException if the user is not allowed to make this update.
205 InputException if some request parameters are required and missing or
206 invalid.
207 """
208 if not request.update_mask:
209 raise exceptions.InputException('No paths given in `update_mask`.')
210 if not request.hotlist:
211 raise exceptions.InputException('No `hotlist` param given.')
212
213 if not request.update_mask.IsValidForDescriptor(
214 feature_objects_pb2.Hotlist.DESCRIPTOR):
215 raise exceptions.InputException('Invalid `update_mask` for `hotlist`')
216
217 hotlist_id = rnc.IngestHotlistName(request.hotlist.name)
218
219 update_args = {}
220 hotlist = request.hotlist
221 for path in request.update_mask.paths:
222 if path == 'display_name':
223 update_args['hotlist_name'] = hotlist.display_name
224 elif path == 'owner':
225 owner_id = rnc.IngestUserName(mc.cnxn, hotlist.owner, self.services)
226 update_args['owner_id'] = owner_id
227 elif path == 'editors':
228 add_editor_ids = rnc.IngestUserNames(
229 mc.cnxn, hotlist.editors, self.services)
230 update_args['add_editor_ids'] = add_editor_ids
231 elif path == 'summary':
232 update_args['summary'] = hotlist.summary
233 elif path == 'description':
234 update_args['description'] = hotlist.description
235 elif path == 'hotlist_privacy':
236 update_args['is_private'] = (
237 hotlist.hotlist_privacy == feature_objects_pb2.Hotlist
238 .HotlistPrivacy.Value('PRIVATE'))
239 elif path == 'default_columns':
240 update_args[
241 'default_col_spec'] = self.converter.IngestIssuesListColumns(
242 hotlist.default_columns)
243
244 with work_env.WorkEnv(mc, self.services) as we:
245 we.UpdateHotlist(hotlist_id, **update_args)
246 hotlist = we.GetHotlist(hotlist_id, use_cache=False)
247
248 return self.converter.ConvertHotlist(hotlist)
249
250 @monorail_servicer.PRPCMethod
251 def DeleteHotlist(self, mc, request):
252 # type: (MonorailContext, GetHotlistRequest) -> Empty
253 """pRPC API method that implements DeleteHotlist.
254
255 Raises:
256 InputException if the given name does not have a valid format.
257 NoSuchHotlistException if the hotlist is not found.
258 PermissionException if the user is not allowed to delete the hotlist.
259 """
260
261 hotlist_id = rnc.IngestHotlistName(request.name)
262
263 with work_env.WorkEnv(mc, self.services) as we:
264 we.DeleteHotlist(hotlist_id)
265
266 return empty_pb2.Empty()