Project import generated by Copybara.
GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/api/projects_servicer.py b/api/projects_servicer.py
new file mode 100644
index 0000000..640a433
--- /dev/null
+++ b/api/projects_servicer.py
@@ -0,0 +1,341 @@
+# Copyright 2018 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
+
+import logging
+
+import settings
+
+from api import monorail_servicer
+from api import converters
+from api.api_proto import projects_pb2
+from api.api_proto import project_objects_pb2
+from api.api_proto import projects_prpc_pb2
+from businesslogic import work_env
+from framework import framework_bizobj
+from framework import exceptions
+from framework import framework_views
+from framework import permissions
+from project import project_helpers
+from tracker import tracker_bizobj
+from tracker import tracker_helpers
+
+# TODO(zhangtiff): Remove dependency on tracker_views.
+from tracker import tracker_views
+
+
+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 that does any request-specific validation, uses work_env to
+ safely operate on business objects, and returns a response proto.
+ """
+
+ DESCRIPTION = projects_prpc_pb2.ProjectsServiceDescription
+
+ def _GetProject(self, mc, request, use_cache=True):
+ """Get the project object specified in the request."""
+ with work_env.WorkEnv(mc, self.services, phase='getting project') as we:
+ project = we.GetProjectByName(request.project_name, use_cache=use_cache)
+ # Perms in this project are already looked up in MonorailServicer.
+ return project
+
+ @monorail_servicer.PRPCMethod
+ def ListProjects(self, _mc, _request):
+ return projects_pb2.ListProjectsResponse(
+ projects=[
+ project_objects_pb2.Project(name='One'),
+ project_objects_pb2.Project(name='Two')],
+ next_page_token='next...')
+
+ @monorail_servicer.PRPCMethod
+ def ListProjectTemplates(self, mc, request):
+ """Return the specific project's templates."""
+ if not request.project_name:
+ raise exceptions.InputException('Param `project_name` required.')
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ config = we.GetProjectConfig(project.project_id)
+ templates = we.ListProjectTemplates(project.project_id)
+
+ with mc.profiler.Phase('converting to response objects'):
+ involved_user_ids = tracker_bizobj.UsersInvolvedInTemplates(templates)
+ users_by_id = framework_views.MakeAllUserViews(
+ mc.cnxn, self.services.user, involved_user_ids)
+ response = projects_pb2.ListProjectTemplatesResponse(
+ templates=converters.ConvertProjectTemplateDefs(
+ templates, users_by_id, config))
+
+ return response
+
+ @monorail_servicer.PRPCMethod
+ def GetConfig(self, mc, request):
+ """Return the specified project config."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ config = we.GetProjectConfig(project.project_id)
+
+ with mc.profiler.Phase('making user views'):
+ involved_user_ids = tracker_bizobj.UsersInvolvedInConfig(config)
+ users_by_id = framework_views.MakeAllUserViews(
+ mc.cnxn, self.services.user, involved_user_ids)
+ framework_views.RevealAllEmailsToMembers(
+ mc.cnxn, self.services, mc.auth, users_by_id, project)
+
+ label_ids = tracker_bizobj.LabelIDsInvolvedInConfig(config)
+ labels_by_id = {
+ label_id: self.services.config.LookupLabel(
+ mc.cnxn, config.project_id, label_id)
+ for label_id in label_ids}
+
+ result = converters.ConvertConfig(
+ project, config, users_by_id, labels_by_id)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def GetPresentationConfig(self, mc, request):
+ """Return the UI centric pieces of the project config."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ config = we.GetProjectConfig(project.project_id)
+
+ project_thumbnail_url = tracker_views.LogoView(project).thumbnail_url
+ project_summary = project.summary
+ custom_issue_entry_url = config.custom_issue_entry_url
+ revision_url_format = (
+ project.revision_url_format or settings.revision_url_format)
+
+ default_query = None
+ saved_queries = None
+
+ # Only show default query or project saved queries for project
+ # members, in case they contain sensitive information.
+ if framework_bizobj.UserIsInProject(
+ project, mc.auth.effective_ids):
+ default_query = config.member_default_query
+
+ saved_queries = self.services.features.GetCannedQueriesByProjectID(
+ mc.cnxn, project.project_id)
+
+ return project_objects_pb2.PresentationConfig(
+ project_thumbnail_url=project_thumbnail_url,
+ project_summary=project_summary,
+ custom_issue_entry_url=custom_issue_entry_url,
+ default_query=default_query,
+ default_col_spec=config.default_col_spec,
+ default_sort_spec=config.default_sort_spec,
+ default_x_attr=config.default_x_attr,
+ default_y_attr=config.default_y_attr,
+ saved_queries=converters.IngestSavedQueries(
+ mc.cnxn, self.services.project, saved_queries),
+ revision_url_format=revision_url_format)
+
+ @monorail_servicer.PRPCMethod
+ def GetCustomPermissions(self, mc, request):
+ """Return the custom permissions for the given project."""
+ project = self._GetProject(mc, request)
+ custom_permissions = permissions.GetCustomPermissions(project)
+
+ result = projects_pb2.GetCustomPermissionsResponse(
+ permissions=custom_permissions)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def GetVisibleMembers(self, mc, request):
+ """Return the members of the project that the user can see.
+
+ Raises:
+ PermissionException the user is not allowed to view the project members.
+ """
+ project = self._GetProject(mc, request)
+ if not permissions.CanViewContributorList(mc, project):
+ raise permissions.PermissionException(
+ 'User is not allowed to view the project members')
+
+ users_by_id = tracker_helpers.GetVisibleMembers(mc, project, self.services)
+
+ sorted_user_ids = sorted(
+ users_by_id, key=lambda uid: users_by_id[uid].email)
+ user_refs = converters.ConvertUserRefs(
+ sorted_user_ids, [], users_by_id, True)
+ sorted_group_ids = sorted(
+ (uv.user_id for uv in users_by_id.values() if uv.is_group),
+ key=lambda uid: users_by_id[uid].email)
+ group_refs = converters.ConvertUserRefs(
+ sorted_group_ids, [], users_by_id, True)
+
+ result = projects_pb2.GetVisibleMembersResponse(
+ user_refs=user_refs, group_refs=group_refs)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def GetLabelOptions(self, mc, request):
+ """Return the label options for autocomplete for the given project."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ config = we.GetProjectConfig(project.project_id)
+
+ label_options = tracker_helpers.GetLabelOptions(
+ config, permissions.GetCustomPermissions(project))
+ label_defs = [
+ project_objects_pb2.LabelDef(
+ label=label['name'],
+ docstring=label['doc'])
+ for label in label_options]
+
+ result = projects_pb2.GetLabelOptionsResponse(
+ label_options=label_defs,
+ exclusive_label_prefixes=config.exclusive_label_prefixes)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def ListStatuses(self, mc, request):
+ """Return all well-known statuses in the specified project."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ config = we.GetProjectConfig(project.project_id)
+
+ status_defs = [
+ converters.ConvertStatusDef(sd)
+ for sd in config.well_known_statuses]
+ statuses_offer_merge = [
+ converters.ConvertStatusRef(sd.status, None, config)
+ for sd in config.well_known_statuses
+ if sd.status in config.statuses_offer_merge]
+
+ result = projects_pb2.ListStatusesResponse(
+ status_defs=status_defs,
+ statuses_offer_merge=statuses_offer_merge,
+ restrict_to_known=config.restrict_to_known)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def ListComponents(self, mc, request):
+ """Return all component defs in the specified project."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ config = we.GetProjectConfig(project.project_id)
+
+ with mc.profiler.Phase('making user views'):
+ users_by_id = {}
+ if request.include_admin_info:
+ users_involved = tracker_bizobj.UsersInvolvedInConfig(config)
+ users_by_id = framework_views.MakeAllUserViews(
+ mc.cnxn, self.services.user, users_involved)
+ framework_views.RevealAllEmailsToMembers(
+ mc.cnxn, self.services, mc.auth, users_by_id, project)
+
+ with mc.profiler.Phase('looking up labels'):
+ labels_by_id = {}
+ if request.include_admin_info:
+ label_ids = tracker_bizobj.LabelIDsInvolvedInConfig(config)
+ labels_by_id = {
+ label_id: self.services.config.LookupLabel(
+ mc.cnxn, config.project_id, label_id)
+ for label_id in label_ids}
+
+ component_defs = [
+ converters.ConvertComponentDef(
+ cd, users_by_id, labels_by_id, request.include_admin_info)
+ for cd in config.component_defs]
+
+ result = projects_pb2.ListComponentsResponse(
+ component_defs=component_defs)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def ListFields(self, mc, request):
+ """List all fields for the specified project."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ config = we.GetProjectConfig(project.project_id)
+
+ users_by_id = {}
+ users_for_perm = {}
+ # Only look for members if user choices are requested and there are user
+ # fields that need permissions.
+ if request.include_user_choices:
+ perms_needed = {
+ fd.needs_perm
+ for fd in config.field_defs
+ if fd.needs_perm and not fd.is_deleted}
+ if perms_needed:
+ users_by_id = tracker_helpers.GetVisibleMembers(
+ mc, project, self.services)
+ effective_ids_by_user = self.services.usergroup.LookupAllMemberships(
+ mc.cnxn, users_by_id)
+ users_for_perm = project_helpers.UsersWithPermsInProject(
+ project, perms_needed, users_by_id, effective_ids_by_user)
+
+ field_defs = [
+ converters.ConvertFieldDef(
+ fd, users_for_perm.get(fd.needs_perm, []), users_by_id, config,
+ request.include_admin_info)
+ for fd in config.field_defs
+ if not fd.is_deleted]
+
+ result = projects_pb2.ListFieldsResponse(field_defs=field_defs)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def GetProjectStarCount(self, mc, request):
+ """Get the star count for the specified project."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ star_count = we.GetProjectStarCount(project.project_id)
+
+ result = projects_pb2.GetProjectStarCountResponse(star_count=star_count)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def StarProject(self, mc, request):
+ """Star the specified project."""
+ project = self._GetProject(mc, request)
+
+ with work_env.WorkEnv(mc, self.services) as we:
+ we.StarProject(project.project_id, request.starred)
+ star_count = we.GetProjectStarCount(project.project_id)
+
+ result = projects_pb2.StarProjectResponse(star_count=star_count)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def CheckProjectName(self, mc, request):
+ """Check that a project name is valid and not already in use."""
+ with work_env.WorkEnv(mc, self.services) as we:
+ error = we.CheckProjectName(request.project_name)
+ result = projects_pb2.CheckProjectNameResponse(error=error)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def CheckComponentName(self, mc, request):
+ """Check that the component name is valid and not already in use."""
+ project = self._GetProject(mc, request)
+ with work_env.WorkEnv(mc, self.services) as we:
+ error = we.CheckComponentName(
+ project.project_id, request.parent_path, request.component_name)
+ result = projects_pb2.CheckComponentNameResponse(error=error)
+ return result
+
+ @monorail_servicer.PRPCMethod
+ def CheckFieldName(self, mc, request):
+ """Check that a field name is valid and not already in use."""
+ project = self._GetProject(mc, request)
+ with work_env.WorkEnv(mc, self.services) as we:
+ error = we.CheckFieldName(project.project_id, request.field_name)
+ result = projects_pb2.CheckFieldNameResponse(error=error)
+ return result