blob: 9267f1d13deb03bda7dc2ec0d989279d29206bea [file] [log] [blame]
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file or at
# https://developers.google.com/open-source/licenses/bsd
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from google.protobuf import empty_pb2
from api import resource_name_converters as rnc
from api.v3 import api_constants
from api.v3 import monorail_servicer
from api.v3 import paginator
from api.v3.api_proto import projects_pb2
from api.v3.api_proto import projects_prpc_pb2
from businesslogic import work_env
class ProjectsServicer(monorail_servicer.MonorailServicer):
"""Handle API requests related to Project objects.
Each API request is implemented with a method as defined in the
.proto file. Each method does any request-specific validation, uses work_env
to safely operate on business objects, and returns a response proto.
"""
DESCRIPTION = projects_prpc_pb2.ProjectsServiceDescription
@monorail_servicer.PRPCMethod
def ListIssueTemplates(self, mc, request):
# type: (MonorailContext, ListIssueTemplatesRequest) ->
# ListIssueTemplatesResponse
"""pRPC API method that implements ListIssueTemplates.
Raises:
InputException if the request.parent is invalid.
NoSuchProjectException if no project exists with the given name.
"""
project_id = rnc.IngestProjectName(mc.cnxn, request.parent, self.services)
with work_env.WorkEnv(mc, self.services) as we:
# TODO(crbug/monorail/7614): Eliminate the need to do this lookup.
project = we.GetProject(project_id)
mc.LookupLoggedInUserPerms(project)
templates = we.ListProjectTemplates(project_id)
return projects_pb2.ListIssueTemplatesResponse(
templates=self.converter.ConvertIssueTemplates(project_id, templates))
@monorail_servicer.PRPCMethod
def GetComponentDef(self, mc, request):
# type: (MonorailContext, GetComponentDefRequest) ->
# ComponentDef
"""pRPC API method that implements GetComponentDef.
Raises:
InputException if the request.parent is invalid.
NoSuchProjectException if the parent project is not found.
"""
project_id, component_id = rnc.IngestComponentDefNames(
mc.cnxn, [request.name], self.services)[0]
with work_env.WorkEnv(mc, self.services) as we:
# TODO(crbug/monorail/7614): Eliminate the need to do this lookup.
project = we.GetProject(project_id)
mc.LookupLoggedInUserPerms(project)
component_def = we.GetComponentDef(project_id, component_id)
api_component_def = self.converter.ConvertComponentDef(component_def)
return api_component_def
@monorail_servicer.PRPCMethod
def ListComponentDefs(self, mc, request):
# type: (MonorailContext, ListComponentDefsRequest) ->
# ListComponentDefsResponse
"""pRPC API method that implements ListComponentDefs.
Raises:
InputException if the request.parent is invalid.
NoSuchProjectException if the parent project is not found.
"""
project_id = rnc.IngestProjectName(mc.cnxn, request.parent, self.services)
with work_env.WorkEnv(mc, self.services) as we:
# TODO(crbug/monorail/7614): Eliminate the need to do this lookup.
project = we.GetProject(project_id)
mc.LookupLoggedInUserPerms(project)
page_size = paginator.CoercePageSize(
request.page_size, api_constants.MAX_COMPONENTS_PER_PAGE)
pager = paginator.Paginator(
parent=request.parent, page_size=page_size)
list_result = we.ListComponentDefs(
project_id, page_size, pager.GetStart(request.page_token))
api_component_defs = self.converter.ConvertComponentDefs(
list_result.items, project_id)
return projects_pb2.ListComponentDefsResponse(
component_defs=api_component_defs,
next_page_token=pager.GenerateNextPageToken(list_result.next_start))
@monorail_servicer.PRPCMethod
def CreateComponentDef(self, mc, request):
# type: (MonorailContext, CreateComponentDefRequest) ->
# ComponentDef
"""pRPC API method that implements CreateComponentDef.
Raises:
InputException if the request is invalid.
NoSuchUserException if any given component admins or ccs do not exist.
NoSuchProjectException if the parent project does not exist.
PermissionException if the requester is not allowed to create
this component.
"""
project_id = rnc.IngestProjectName(mc.cnxn, request.parent, self.services)
admin_ids = rnc.IngestUserNames(
mc.cnxn, request.component_def.admins, self.services)
cc_ids = rnc.IngestUserNames(
mc.cnxn, request.component_def.ccs, self.services)
with work_env.WorkEnv(mc, self.services) as we:
component_def = we.CreateComponentDef(
project_id, request.component_def.value,
request.component_def.docstring, admin_ids, cc_ids,
request.component_def.labels)
return self.converter.ConvertComponentDef(component_def)
@monorail_servicer.PRPCMethod
def DeleteComponentDef(self, mc, request):
# type: (MonorailContext, DeleteComponentDefRequest) -> Empty
"""pRPC API method that implements DeleteComponentDef.
Raises:
InputException if the request in invalid.
NoSuchComponentException if the component does not exist.
PermissionException if the requester is not allowed to delete
this component.
NoSuchProjectException if the parent project does not exist.
"""
project_id, component_id = rnc.IngestComponentDefNames(
mc.cnxn, [request.name], self.services)[0]
with work_env.WorkEnv(mc, self.services) as we:
we.DeleteComponentDef(project_id, component_id)
return empty_pb2.Empty()
@monorail_servicer.PRPCMethod
def ListProjects(self, mc, _):
# type: (MonorailContext, ListProjectsRequest) -> ListProjectsResponse
"""pRPC API method that implements ListProjects.
Raises:
InputException if the request.page_token is invalid or the request does
not match the previous request that provided the given page_token.
"""
with work_env.WorkEnv(mc, self.services) as we:
# NOTE(crbug/monorail/7614): Until the referenced cleanup is complete,
# all servicer methods that are scoped to a single Project need to call
# mc.LookupLoggedInUserPerms.
# This method does not because it may be scoped to multiple projects.
allowed_project_ids = we.ListProjects()
projects_dict = we.GetProjects(allowed_project_ids)
projects = [projects_dict[proj_id] for proj_id in allowed_project_ids]
# TODO(crbug.com/monorail/7505): Add pagination logic.
return projects_pb2.ListProjectsResponse(
projects=self.converter.ConvertProjects(projects))