Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2282)

Unified Diff: appengine/monorail/search/backendnonviewable.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « appengine/monorail/search/ast2sort.py ('k') | appengine/monorail/search/backendsearch.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/monorail/search/backendnonviewable.py
diff --git a/appengine/monorail/search/backendnonviewable.py b/appengine/monorail/search/backendnonviewable.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7ec0a11a30ee43dcc59e62c1d7a42d80a875474
--- /dev/null
+++ b/appengine/monorail/search/backendnonviewable.py
@@ -0,0 +1,143 @@
+# 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
+
+"""Servlet that searches for issues that the specified user cannot view.
+
+The GET request to a backend has query string parameters for the
+shard_id, a user_id, and list of project IDs. It returns a
+JSON-formatted dict with issue_ids that that user is not allowed to
+view. As a side-effect, this servlet updates multiple entries
+in memcache, including each "nonviewable:USER_ID;PROJECT_ID;SHARD_ID".
+"""
+
+import logging
+
+from google.appengine.api import memcache
+
+from framework import framework_constants
+from framework import framework_helpers
+from framework import jsonfeed
+from framework import permissions
+from framework import sql
+
+
+RESTRICT_VIEW_PATTERN = 'restrict-view-%'
+
+# We cache the set of IIDs that a given user cannot view, and we invalidate
+# that set when the issues are changed via Monorail. Also, we limit the live
+# those cache entries so that changes in a user's (direct or indirect) roles
+# in a project will take effect.
+NONVIEWABLE_MEMCACHE_EXPIRATION = 15 * framework_constants.SECS_PER_MINUTE
+
+
+class BackendNonviewable(jsonfeed.InternalTask):
+ """JSON servlet for getting issue IDs that the specified user cannot view."""
+
+ CHECK_SAME_APP = True
+
+ def HandleRequest(self, mr):
+ """Get all the user IDs that the specified user cannot view.
+
+ Args:
+ mr: common information parsed from the HTTP request.
+
+ Returns:
+ Results dictionary {project_id: [issue_id]} in JSON format.
+ """
+ if mr.shard_id is None:
+ return {'message': 'Cannot proceed without a valid shard_id.'}
+ user_id = mr.specified_logged_in_user_id
+ user = self.services.user.GetUser(mr.cnxn, user_id)
+ effective_ids = self.services.usergroup.LookupMemberships(mr.cnxn, user_id)
+ if user_id:
+ effective_ids.add(user_id)
+ project_id = mr.specified_project_id
+ project = self.services.project.GetProject(mr.cnxn, project_id)
+
+ perms = permissions.GetPermissions(user, effective_ids, project)
+
+ nonviewable_iids = self.GetNonviewableIIDs(
+ mr.cnxn, user, effective_ids, project, perms, mr.shard_id)
+
+ cached_ts = mr.invalidation_timestep
+ if mr.specified_project_id:
+ memcache.set(
+ 'nonviewable:%d;%d;%d' % (project_id, user_id, mr.shard_id),
+ (nonviewable_iids, cached_ts),
+ time=NONVIEWABLE_MEMCACHE_EXPIRATION)
+ else:
+ memcache.set(
+ 'nonviewable:all;%d;%d' % (user_id, mr.shard_id),
+ (nonviewable_iids, cached_ts),
+ time=NONVIEWABLE_MEMCACHE_EXPIRATION)
+
+ logging.info('set nonviewable:%s;%d;%d to %r', project_id, user_id,
+ mr.shard_id, nonviewable_iids)
+
+ return {
+ 'nonviewable': nonviewable_iids,
+
+ # These are not used in the frontend, but useful for debugging.
+ 'project_id': project_id,
+ 'user_id': user_id,
+ 'shard_id': mr.shard_id,
+ }
+
+ def GetNonviewableIIDs(
+ self, cnxn, user, effective_ids, project, perms, shard_id):
+ """Return a list of IIDs that the user cannot view in the project shard."""
+ # Project owners and site admins can see all issues.
+ if not perms.consider_restrictions:
+ return []
+
+ # There are two main parts to the computation that we do in parallel:
+ # getting at-risk IIDs and getting OK-iids.
+ cnxn_2 = sql.MonorailConnection()
+ at_risk_iids_promise = framework_helpers.Promise(
+ self.GetAtRiskIIDs, cnxn_2, user, effective_ids, project, perms, shard_id)
+ ok_iids = self.GetViewableIIDs(
+ cnxn, effective_ids, project.project_id, shard_id)
+ at_risk_iids = at_risk_iids_promise.WaitAndGetValue()
+
+ # The set of non-viewable issues is the at-risk ones minus the ones where
+ # the user is the reporter, owner, CC'd, or granted "View" permission.
+ nonviewable_iids = set(at_risk_iids).difference(ok_iids)
+
+ return list(nonviewable_iids)
+
+ def GetAtRiskIIDs(
+ self, cnxn, user, effective_ids, project, perms, shard_id):
+ """Return IIDs of restricted issues that user might not be able to view."""
+ at_risk_label_ids = self.GetPersonalAtRiskLabelIDs(
+ cnxn, user, effective_ids, project, perms)
+ at_risk_iids = self.services.issue.GetIIDsByLabelIDs(
+ cnxn, at_risk_label_ids, project.project_id, shard_id)
+
+ return at_risk_iids
+
+ def GetPersonalAtRiskLabelIDs(
+ self, cnxn, _user, effective_ids, project, perms):
+ """Return list of label_ids for restriction labels that user can't view."""
+ at_risk_label_ids = []
+ label_def_rows = self.services.config.GetLabelDefRowsAnyProject(
+ cnxn, where=[('LOWER(label) LIKE %s', [RESTRICT_VIEW_PATTERN])])
+ for label_id, _pid, _rank, label, _docstring, _hidden in label_def_rows:
+ label_lower = label.lower()
+ needed_perm = label_lower.split('-', 2)[-1]
+ if not perms.CanUsePerm(needed_perm, effective_ids, project, []):
+ at_risk_label_ids.append(label_id)
+
+ return at_risk_label_ids
+
+ def GetViewableIIDs(self, cnxn, effective_ids, project_id, shard_id):
+ """Return IIDs of issues that user can view because they participate."""
+ # Anon user is never reporter, owner, CC'd or granted perms.
+ if not effective_ids:
+ return []
+
+ ok_iids = self.services.issue.GetIIDsByParticipant(
+ cnxn, effective_ids, [project_id], shard_id)
+
+ return ok_iids
« no previous file with comments | « appengine/monorail/search/ast2sort.py ('k') | appengine/monorail/search/backendsearch.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698