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

Unified Diff: appengine/monorail/sitewide/groupdetail.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/sitewide/groupcreate.py ('k') | appengine/monorail/sitewide/grouplist.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: appengine/monorail/sitewide/groupdetail.py
diff --git a/appengine/monorail/sitewide/groupdetail.py b/appengine/monorail/sitewide/groupdetail.py
new file mode 100644
index 0000000000000000000000000000000000000000..4d66e0336b335df53d6cba06bd5afa89f7f2dfe7
--- /dev/null
+++ b/appengine/monorail/sitewide/groupdetail.py
@@ -0,0 +1,196 @@
+# 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
+
+"""A class to display a user group, including a paginated list of members."""
+
+import logging
+import time
+
+from third_party import ezt
+
+from framework import framework_helpers
+from framework import framework_views
+from framework import paginate
+from framework import permissions
+from framework import servlet
+from project import project_helpers
+from proto import usergroup_pb2
+from services import usergroup_svc
+from sitewide import group_helpers
+from sitewide import sitewide_views
+
+MEMBERS_PER_PAGE = 50
+
+
+class GroupDetail(servlet.Servlet):
+ """The group detail page presents information about one user group."""
+
+ _PAGE_TEMPLATE = 'sitewide/group-detail-page.ezt'
+
+ def AssertBasePermission(self, mr):
+ """Assert that the user has the permissions needed to view this page."""
+ super(GroupDetail, self).AssertBasePermission(mr)
+
+ group_id = mr.viewed_user_auth.user_id
+ group_settings = self.services.usergroup.GetGroupSettings(
+ mr.cnxn, group_id)
+
+ member_ids, owner_ids = self.services.usergroup.LookupAllMembers(
+ mr.cnxn, [group_id])
+ (owned_project_ids, membered_project_ids,
+ contrib_project_ids) = self.services.project.GetUserRolesInAllProjects(
+ mr.cnxn, mr.auth.effective_ids)
+ project_ids = owned_project_ids.union(
+ membered_project_ids).union(contrib_project_ids)
+ if not permissions.CanViewGroup(
+ mr.perms, mr.auth.effective_ids, group_settings, member_ids[group_id],
+ owner_ids[group_id], project_ids):
+ raise permissions.PermissionException(
+ 'User is not allowed to view a user group')
+
+ def GatherPageData(self, mr):
+ """Build up a dictionary of data values to use when rendering the page."""
+ group_id = mr.viewed_user_auth.user_id
+ group_settings = self.services.usergroup.GetGroupSettings(
+ mr.cnxn, group_id)
+
+ member_ids_dict, owner_ids_dict = (
+ self.services.usergroup.LookupVisibleMembers(
+ mr.cnxn, [group_id], mr.perms, mr.auth.effective_ids,
+ self.services))
+ member_ids = member_ids_dict[group_id]
+ owner_ids = owner_ids_dict[group_id]
+ member_pbs_dict = self.services.user.GetUsersByIDs(
+ mr.cnxn, member_ids)
+ owner_pbs_dict = self.services.user.GetUsersByIDs(
+ mr.cnxn, owner_ids)
+ member_dict = {}
+ for user_id, user_pb in member_pbs_dict.iteritems():
+ member_view = group_helpers.GroupMemberView(
+ user_id, user_pb.email, user_pb.obscure_email, group_id, 'member')
+ member_dict[user_id] = member_view
+ owner_dict = {}
+ for user_id, user_pb in owner_pbs_dict.iteritems():
+ member_view = group_helpers.GroupMemberView(
+ user_id, user_pb.email, user_pb.obscure_email, group_id, 'owner')
+ owner_dict[user_id] = member_view
+
+ member_user_views = []
+ member_user_views.extend(
+ sorted(owner_dict.values(), key=lambda u: u.email))
+ member_user_views.extend(
+ sorted(member_dict.values(), key=lambda u: u.email))
+
+ group_view = sitewide_views.GroupView(
+ mr.viewed_user_auth.email, len(member_ids), group_settings,
+ mr.viewed_user_auth.user_id)
+ pagination = paginate.ArtifactPagination(
+ mr, member_user_views, MEMBERS_PER_PAGE, group_view.detail_url)
+
+ is_imported_group = bool(group_settings.ext_group_type)
+
+ offer_membership_editing = permissions.CanEditGroup(
+ mr.perms, mr.auth.effective_ids, owner_ids) and not is_imported_group
+
+ return {
+ 'admin_tab_mode': self.ADMIN_TAB_META,
+ 'offer_membership_editing': ezt.boolean(offer_membership_editing),
+ 'initial_add_members': '',
+ 'initially_expand_form': ezt.boolean(False),
+ 'groupid': group_id,
+ 'groupname': mr.viewed_username,
+ 'settings': group_settings,
+ 'pagination': pagination,
+ }
+
+ def ProcessFormData(self, mr, post_data):
+ """Process the posted form."""
+ _, owner_ids_dict = self.services.usergroup.LookupMembers(
+ mr.cnxn, [mr.viewed_user_auth.user_id])
+ owner_ids = owner_ids_dict[mr.viewed_user_auth.user_id]
+ permit_edit = permissions.CanEditGroup(
+ mr.perms, mr.auth.effective_ids, owner_ids)
+ if not permit_edit:
+ raise permissions.PermissionException(
+ 'User is not permitted to edit group membership')
+
+ group_settings = self.services.usergroup.GetGroupSettings(
+ mr.cnxn, mr.viewed_user_auth.user_id)
+ if bool(group_settings.ext_group_type):
+ raise permissions.PermissionException(
+ 'Imported groups are read-only')
+
+ if 'addbtn' in post_data:
+ return self.ProcessAddMembers(mr, post_data)
+ elif 'removebtn' in post_data:
+ return self.ProcessRemoveMembers(mr, post_data)
+
+ def ProcessAddMembers(self, mr, post_data):
+ """Process the user's request to add members.
+
+ Args:
+ mr: common information parsed from the HTTP request.
+ post_data: dictionary of form data.
+
+ Returns:
+ String URL to redirect the user to after processing.
+ """
+ # 1. Gather data from the request.
+ group_id = mr.viewed_user_auth.user_id
+ add_members_str = post_data.get('addmembers')
+ new_member_ids = project_helpers.ParseUsernames(
+ mr.cnxn, self.services.user, add_members_str)
+ role = post_data['role']
+
+ # 2. Call services layer to save changes.
+ if not mr.errors.AnyErrors():
+ try:
+ self.services.usergroup.UpdateMembers(
+ mr.cnxn, group_id, new_member_ids, role)
+ except usergroup_svc.CircularGroupException:
+ mr.errors.addmembers = (
+ 'The members are already ancestors of current group.')
+
+ # 3. Determine the next page in the UI flow.
+ if mr.errors.AnyErrors():
+ self.PleaseCorrect(
+ mr, initial_add_members=add_members_str,
+ initially_expand_form=ezt.boolean(True))
+ else:
+ return framework_helpers.FormatAbsoluteURL(
+ mr, '/g/%s/' % mr.viewed_username, include_project=False,
+ saved=1, ts=int(time.time()))
+
+ def ProcessRemoveMembers(self, mr, post_data):
+ """Process the user's request to remove members.
+
+ Args:
+ mr: common information parsed from the HTTP request.
+ post_data: dictionary of form data.
+
+ Returns:
+ String URL to redirect the user to after processing.
+ """
+ # 1. Gather data from the request.
+ remove_strs = post_data.getall('remove')
+ logging.info('remove_strs = %r', remove_strs)
+
+ if not remove_strs:
+ mr.errors.remove = 'No users specified'
+
+ # 2. Call services layer to save changes.
+ if not mr.errors.AnyErrors():
+ remove_ids = set(
+ self.services.user.LookupUserIDs(mr.cnxn, remove_strs).values())
+ self.services.usergroup.RemoveMembers(
+ mr.cnxn, mr.viewed_user_auth.user_id, remove_ids)
+
+ # 3. Determine the next page in the UI flow.
+ if mr.errors.AnyErrors():
+ self.PleaseCorrect(mr)
+ else:
+ return framework_helpers.FormatAbsoluteURL(
+ mr, '/g/%s/' % mr.viewed_username, include_project=False,
+ saved=1, ts=int(time.time()))
« no previous file with comments | « appengine/monorail/sitewide/groupcreate.py ('k') | appengine/monorail/sitewide/grouplist.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698