| Index: appengine/monorail/sitewide/sitewide_helpers.py
|
| diff --git a/appengine/monorail/sitewide/sitewide_helpers.py b/appengine/monorail/sitewide/sitewide_helpers.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9ebb983941ec517fafb4fdac3d8e8f5ebb2676a2
|
| --- /dev/null
|
| +++ b/appengine/monorail/sitewide/sitewide_helpers.py
|
| @@ -0,0 +1,122 @@
|
| +# Copyright 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is govered by a BSD-style
|
| +# license that can be found in the LICENSE file or at
|
| +# https://developers.google.com/open-source/licenses/bsd
|
| +
|
| +"""Helper functions used in sitewide servlets."""
|
| +
|
| +import logging
|
| +
|
| +from framework import permissions
|
| +from proto import project_pb2
|
| +
|
| +
|
| +def GetViewableStarredProjects(
|
| + cnxn, services, viewed_user_id, effective_ids, logged_in_user):
|
| + """Returns a list of viewable starred projects."""
|
| + starred_project_ids = services.project_star.LookupStarredItemIDs(
|
| + cnxn, viewed_user_id)
|
| + projects = services.project.GetProjects(cnxn, starred_project_ids).values()
|
| + viewable_projects = FilterViewableProjects(
|
| + projects, logged_in_user, effective_ids)
|
| + return viewable_projects
|
| +
|
| +
|
| +def FilterViewableProjects(project_list, logged_in_user, effective_ids):
|
| + """Return subset of LIVE project protobufs viewable by the given user."""
|
| + viewable_projects = []
|
| + for project in project_list:
|
| + if (project.state == project_pb2.ProjectState.LIVE and
|
| + permissions.UserCanViewProject(
|
| + logged_in_user, effective_ids, project)):
|
| + viewable_projects.append(project)
|
| +
|
| + return viewable_projects
|
| +
|
| +
|
| +def GetUserProjects(
|
| + cnxn, services, user, effective_ids, viewed_user_effective_ids):
|
| + """Get the projects to display in the user's profile.
|
| +
|
| + Args:
|
| + cnxn: connection to the SQL database.
|
| + services: An instance of services
|
| + user: The user doing the viewing.
|
| + effective_ids: set of int user IDs of the user viewing the projects
|
| + (including any user group IDs).
|
| + viewed_user_effective_ids: set of int user IDs of the user being viewed.
|
| +
|
| + Returns:
|
| + A 4-tuple of lists of PBs:
|
| + - live projects the viewed user owns
|
| + - archived projects the viewed user owns
|
| + - live projects the viewed user is a member of
|
| + - live projects the viewed user is a contributor to
|
| +
|
| + Any projects the viewing user should not be able to see are filtered out.
|
| + Admins can see everything, while other users can see all non-locked
|
| + projects they own or are a member of, as well as all live projects.
|
| + """
|
| + (owned_project_ids, membered_project_ids,
|
| + contrib_project_ids) = services.project.GetUserRolesInAllProjects(
|
| + cnxn, viewed_user_effective_ids)
|
| +
|
| + # Each project should only be considered for at most one role category.
|
| + # We keep the highest ranking roles and discard lower-ranking ones.
|
| + membered_project_ids.difference_update(owned_project_ids)
|
| + contrib_project_ids.difference_update(owned_project_ids)
|
| + contrib_project_ids.difference_update(membered_project_ids)
|
| +
|
| + # Build a dictionary of (project_id -> project)
|
| + # so that we can check permissions.
|
| + combined = owned_project_ids.union(membered_project_ids).union(
|
| + contrib_project_ids)
|
| + projects_dict = services.project.GetProjects(cnxn, combined)
|
| + projects_dict = _FilterProjectDict(user, effective_ids, projects_dict)
|
| +
|
| + visible_ownership = _PickProjects(owned_project_ids, projects_dict)
|
| + visible_archived = _PickProjects(
|
| + owned_project_ids, projects_dict, archived=True)
|
| + visible_membership = _PickProjects(membered_project_ids, projects_dict)
|
| + visible_contrib = _PickProjects(contrib_project_ids, projects_dict)
|
| +
|
| + return (_SortProjects(visible_ownership), _SortProjects(visible_archived),
|
| + _SortProjects(visible_membership), _SortProjects(visible_contrib))
|
| +
|
| +
|
| +def _SortProjects(projects):
|
| + return sorted(projects, key=lambda p: p.project_name)
|
| +
|
| +
|
| +def _PickProjects(project_ids, projects_dict, archived=False):
|
| + """Select the projects named in project_ids from a preloaded dictionary.
|
| +
|
| + Args:
|
| + project_ids: list of project_ids for the desired projects.
|
| + projects_dict: dict {project_id: ProjectPB, ...} of a lot
|
| + of preloaded projects, including all the desired ones that exist.
|
| + archived: set to True if you want to return projects that are in a
|
| + ARCHIVED state instead of those that are not.
|
| +
|
| + Returns:
|
| + A list of Project PBs for the desired projects. If one of them is
|
| + not found in projects_dict, it is ignored.
|
| + """
|
| + # Done in 3 steps: lookup all existing requested projects, filter out
|
| + # DELETABLE ones, then filter out ARCHIVED or non-ARCHIVED.
|
| + results = [projects_dict.get(pid) for pid in project_ids
|
| + if pid in projects_dict]
|
| + results = [proj for proj in results
|
| + if proj.state != project_pb2.ProjectState.DELETABLE]
|
| + results = [proj for proj in results
|
| + if archived == (proj.state == project_pb2.ProjectState.ARCHIVED)]
|
| + return results
|
| +
|
| +
|
| +def _FilterProjectDict(user, effective_ids, projects_dict):
|
| + """Return a new project dictionary which contains only viewable projects."""
|
| + return {
|
| + pid: project
|
| + for pid, project in projects_dict.iteritems()
|
| + if permissions.UserCanViewProject(user, effective_ids, project)
|
| + }
|
|
|