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