blob: 17d6f9368adb0188f6f4642579d41a808fcaf25a [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 api_constants
14from api.v3 import monorail_servicer
15from api.v3 import paginator
16from api.v3.api_proto import projects_pb2
17from api.v3.api_proto import projects_prpc_pb2
18from businesslogic import work_env
19
20
21class ProjectsServicer(monorail_servicer.MonorailServicer):
22 """Handle API requests related to Project objects.
23 Each API request is implemented with a method as defined in the
24 .proto file. Each method does any request-specific validation, uses work_env
25 to safely operate on business objects, and returns a response proto.
26 """
27
28 DESCRIPTION = projects_prpc_pb2.ProjectsServiceDescription
29
30 @monorail_servicer.PRPCMethod
31 def ListIssueTemplates(self, mc, request):
32 # type: (MonorailContext, ListIssueTemplatesRequest) ->
33 # ListIssueTemplatesResponse
34 """pRPC API method that implements ListIssueTemplates.
35
36 Raises:
37 InputException if the request.parent is invalid.
38 NoSuchProjectException if no project exists with the given name.
39 """
40 project_id = rnc.IngestProjectName(mc.cnxn, request.parent, self.services)
41
42 with work_env.WorkEnv(mc, self.services) as we:
43 # TODO(crbug/monorail/7614): Eliminate the need to do this lookup.
44 project = we.GetProject(project_id)
45 mc.LookupLoggedInUserPerms(project)
46 templates = we.ListProjectTemplates(project_id)
47
48 return projects_pb2.ListIssueTemplatesResponse(
49 templates=self.converter.ConvertIssueTemplates(project_id, templates))
50
51 @monorail_servicer.PRPCMethod
52 def ListComponentDefs(self, mc, request):
53 # type: (MonorailContext, ListComponentDefsRequest) ->
54 # ListComponentDefsResponse
55 """pRPC API method that implements ListComponentDefs.
56
57 Raises:
58 InputException if the request.parent is invalid.
59 NoSuchProjectException if the parent project is not found.
60 """
61 project_id = rnc.IngestProjectName(mc.cnxn, request.parent, self.services)
62
63 with work_env.WorkEnv(mc, self.services) as we:
64 # TODO(crbug/monorail/7614): Eliminate the need to do this lookup.
65 project = we.GetProject(project_id)
66 mc.LookupLoggedInUserPerms(project)
67
68 page_size = paginator.CoercePageSize(
69 request.page_size, api_constants.MAX_COMPONENTS_PER_PAGE)
70 pager = paginator.Paginator(
71 parent=request.parent, page_size=page_size)
72 list_result = we.ListComponentDefs(
73 project_id, page_size, pager.GetStart(request.page_token))
74
75 api_component_defs = self.converter.ConvertComponentDefs(
76 list_result.items, project_id)
77
78 return projects_pb2.ListComponentDefsResponse(
79 component_defs=api_component_defs,
80 next_page_token=pager.GenerateNextPageToken(list_result.next_start))
81
82 @monorail_servicer.PRPCMethod
83 def CreateComponentDef(self, mc, request):
84 # type: (MonorailContext, CreateComponentDefRequest) ->
85 # ComponentDef
86 """pRPC API method that implements CreateComponentDef.
87
88 Raises:
89 InputException if the request is invalid.
90 NoSuchUserException if any given component admins or ccs do not exist.
91 NoSuchProjectException if the parent project does not exist.
92 PermissionException if the requester is not allowed to create
93 this component.
94 """
95 project_id = rnc.IngestProjectName(mc.cnxn, request.parent, self.services)
96 admin_ids = rnc.IngestUserNames(
97 mc.cnxn, request.component_def.admins, self.services)
98 cc_ids = rnc.IngestUserNames(
99 mc.cnxn, request.component_def.ccs, self.services)
100
101 with work_env.WorkEnv(mc, self.services) as we:
102 component_def = we.CreateComponentDef(
103 project_id, request.component_def.value,
104 request.component_def.docstring, admin_ids, cc_ids,
105 request.component_def.labels)
106
107 return self.converter.ConvertComponentDef(component_def)
108
109 @monorail_servicer.PRPCMethod
110 def DeleteComponentDef(self, mc, request):
111 # type: (MonorailContext, DeleteComponentDefRequest) -> Empty
112 """pRPC API method that implements DeleteComponentDef.
113
114 Raises:
115 InputException if the request in invalid.
116 NoSuchComponentException if the component does not exist.
117 PermissionException if the requester is not allowed to delete
118 this component.
119 NoSuchProjectException if the parent project does not exist.
120 """
121 project_id, component_id = rnc.IngestComponentDefNames(
122 mc.cnxn, [request.name], self.services)[0]
123
124 with work_env.WorkEnv(mc, self.services) as we:
125 we.DeleteComponentDef(project_id, component_id)
126
127 return empty_pb2.Empty()
128
129 @monorail_servicer.PRPCMethod
130 def ListProjects(self, mc, _):
131 # type: (MonorailContext, ListProjectsRequest) -> ListProjectsResponse
132 """pRPC API method that implements ListProjects.
133
134 Raises:
135 InputException if the request.page_token is invalid or the request does
136 not match the previous request that provided the given page_token.
137 """
138 with work_env.WorkEnv(mc, self.services) as we:
139 # NOTE(crbug/monorail/7614): Until the referenced cleanup is complete,
140 # all servicer methods that are scoped to a single Project need to call
141 # mc.LookupLoggedInUserPerms.
142 # This method does not because it may be scoped to multiple projects.
143 allowed_project_ids = we.ListProjects()
144 projects_dict = we.GetProjects(allowed_project_ids)
145 projects = [projects_dict[proj_id] for proj_id in allowed_project_ids]
146
147 # TODO(crbug.com/monorail/7505): Add pagination logic.
148 return projects_pb2.ListProjectsResponse(
149 projects=self.converter.ConvertProjects(projects))