def user_workspaces(username, context=None, finder=get_workspaces): """ Get workspaces for username, matching only workspaces for which the given user is a member; may be given context or use the site root as default context. A workspace enumerator/finder other than get_workspaces() may be passed (e.g. collective.teamwork.utils.get_projects). """ suffix = '-viewers' site = getSite() context = context or site # get all PAS groups for workspaces contained within context: all_workspaces = finder(context) if not all_workspaces: # context contains no workspaces, even if context itself is workspace return [] _pasgroup = lambda g: g.pas_group() _wgroups = lambda w: map(_pasgroup, IWorkspaceRoster(w).groups.values()) local_groups = set( zip(*itertools.chain(*map(_wgroups, all_workspaces)))[0] ) if not local_groups: return [] # get all '-viewers' groups user belongs to, intersect with local: user = ISiteMembers(site).get(username) usergroups = [name for name in user.getGroups() if name.endswith(suffix)] considered = [name for name in local_groups.intersection(usergroups)] # each considered group (by suffix convention) is always 1:1 with # workspaces, no dupes, so we can map those workspaces: return map(group_workspace, set(considered))
def user_workspaces(username, context=None, finder=get_workspaces): """ Get workspaces for username, matching only workspaces for which the given user is a member; may be given context or use the site root as default context. A workspace enumerator/finder other than get_workspaces() may be passed (e.g. collective.teamwork.utils.get_projects). """ suffix = '-viewers' site = getSite() context = context or site # get all PAS groups for workspaces contained within context: all_workspaces = finder(context) if not all_workspaces: # context contains no workspaces, even if context itself is workspace return [] _pasgroup = lambda g: g.pas_group() _wgroups = lambda w: map(_pasgroup, IWorkspaceRoster(w).groups.values()) local_groups = set( zip(*itertools.chain(*map(_wgroups, all_workspaces)))[0]) if not local_groups: return [] # get all '-viewers' groups user belongs to, intersect with local: user = ISiteMembers(site).get(username) usergroups = [name for name in user.getGroups() if name.endswith(suffix)] considered = [name for name in local_groups.intersection(usergroups)] # each considered group (by suffix convention) is always 1:1 with # workspaces, no dupes, so we can map those workspaces: return map(group_workspace, set(considered))
def __init__(self, context, request): if not IWorkspaceContext.providedBy(context): raise ValueError('Context not a workspace') self.context = context self.request = request self.portal = getSite() self._members = ISiteMembers(self.portal) self._roster = IWorkspaceRoster(self.context) self._mtool = getToolByName(self.portal, 'portal_membership') self._secmgr = None
def add_project(self, id, title=None): project = self.add_check(PROJECT_TYPE, id, IProject, Project) members = ISiteMembers(self.portal) if self.TEST_MEMBER not in members: members.register(self.TEST_MEMBER, send=False) assert self.TEST_MEMBER in members roster = IWorkspaceRoster(project) roster.add(self.TEST_MEMBER) assert self.TEST_MEMBER in roster return project
def fix_current_user(context): """ When a project is added, the current user context may not yet have Manager role added to the generated user object, even if the user is technically a member of the group. This is only an issue when we attempt to do something requiring a group membership added in the same transation. This is a workaround. """ current = ISiteMembers(getSite()).current() roster = IWorkspaceRoster(context) manager_group = roster.groups.get('managers').pas_group()[0] current._addGroups((manager_group,))
def handle_workspace_move_or_rename(context, event): if IObjectRemovedEvent.providedBy(event): return # not a move with new/old, but a removal -- handled elsewhere if IObjectAddedEvent.providedBy(event): return # not an add, but a move of existing site = getSite() pasgroups = ISiteMembers(site).groups roster = WorkspaceRoster(context) for workgroup in roster.groups.values(): groupname, title = workgroup.pas_group() if groupname not in pasgroups: pasgroups.add(groupname, title=title) else: pasgroups.get(groupname).title = _u(title)
def handle_workspace_removal(context, event): """Handler for IObjectRemovedEvent on a workspace""" site = getSite() if site is None: return # in case of recursive plone site removal, ignore pasgroups = ISiteMembers(site).groups roster = WorkspaceRoster(context) for group in roster.groups.values(): groupname = group.pas_group()[0] if groupname in pasgroups: pasgroups.remove(groupname) # remove group names for nested workspaces (also, by implication, # removed from the PAS group manager plugin). for workspace in get_workspaces(context): handle_workspace_removal(workspace, event=event)
def create_workspace_groups_roles(context): site = getSite() members = ISiteMembers(site) pasgroups = members.groups roster = WorkspaceRoster(context) for group in roster.groups.values(): groupname, title = group.pas_group() if groupname not in pasgroups: pasgroups.add(groupname, title=title) else: # update title of previously existing group (edge case) pasgroups.get(groupname).title = _u(title) # bind local roles, mapping group to roles from config sync_group_roles(context, groupname) if INavigationRoot.providedBy(context): # for newly added top-level (nav root workspaces or # projects), add owner/creator as a manager. authuser = members.current() if authuser is not None: authuser = authuser.getUserName() if authuser in members: roster.add(authuser) roster.groups['managers'].add(authuser)
def test_adapter_registration(self): self.assertIsInstance(ISiteMembers(self.portal), SiteMembers) self.assertEqual(ISiteMembers(self.portal).context, self.portal)
class UserInfo(object): """ View for user information -- for a single user. May be used for either display of a single user in an overlay or for a macro listing multiple users (see template). """ RESTRICTED_PROPS = ('last_login_time', ) def __init__(self, context, request): if not IWorkspaceContext.providedBy(context): raise ValueError('Context not a workspace') self.context = context self.request = request self.portal = getSite() self._members = ISiteMembers(self.portal) self._roster = IWorkspaceRoster(self.context) self._mtool = getToolByName(self.portal, 'portal_membership') self._secmgr = None def linked_workspaces(self, username): if self._secmgr is None: self._secmgr = getSecurityManager() # get all workspaces for user in the current context workspaces = user_workspaces(username, self.context) _you_can_see = lambda w: self._secmgr.checkPermission('View', w) _nolink = lambda w: {'absolute_url': '#', 'Title': w.Title()} # only provide links to workspaces the current auth. user can View: return [(w if _you_can_see(w) else _nolink(w)) for w in workspaces] def user_display_info(self, username): """ Given username, get information for that user, returning it as a dict of portrait_url (if existing), properties, assignments (in this workspace), and memberships (in contained workspaces). """ if self._secmgr is None: self._secmgr = getSecurityManager() roster = self._roster data = {} # use dict in lieu of object, simple user = self._members.get(username, None) if user is None or username not in roster: return data # empty if no user data or user not in workspace portrait = self._members.portrait_for(username) if portrait is not None: data['portrait_url'] = portrait.absolute_url() propkeys = { 'fullname': 'Full name', 'email': 'Email', 'description': 'User info', 'location': 'Location', 'home_page': 'Home page', 'last_login_time': 'Last login', } restricted = self.RESTRICTED_PROPS if self._secmgr.checkPermission('Manage users', self.context): restricted = () # manager can see these properties if self._mtool.getAuthenticatedMember().getId() == username: restricted = () # user can see own restricted properties props = {} for name, title in propkeys.items(): if name in restricted: continue v = user.getProperty(name) if v: props[title] = v if props: data['properties'] = props groups = roster.groups.values() data['assignments'] = [g.title for g in groups if username in g] workspaces = self.linked_workspaces(username) if workspaces: data['workspaces'] = workspaces return data
class UserInfo(object): """ View for user information -- for a single user. May be used for either display of a single user in an overlay or for a macro listing multiple users (see template). """ RESTRICTED_PROPS = ( 'last_login_time', ) def __init__(self, context, request): if not IWorkspaceContext.providedBy(context): raise ValueError('Context not a workspace') self.context = context self.request = request self.portal = getSite() self._members = ISiteMembers(self.portal) self._roster = IWorkspaceRoster(self.context) self._mtool = getToolByName(self.portal, 'portal_membership') self._secmgr = None def linked_workspaces(self, username): if self._secmgr is None: self._secmgr = getSecurityManager() # get all workspaces for user in the current context workspaces = user_workspaces(username, self.context) _you_can_see = lambda w: self._secmgr.checkPermission('View', w) _nolink = lambda w: {'absolute_url': '#', 'Title': w.Title()} # only provide links to workspaces the current auth. user can View: return [ (w if _you_can_see(w) else _nolink(w)) for w in workspaces ] def user_display_info(self, username): """ Given username, get information for that user, returning it as a dict of portrait_url (if existing), properties, assignments (in this workspace), and memberships (in contained workspaces). """ if self._secmgr is None: self._secmgr = getSecurityManager() roster = self._roster data = {} # use dict in lieu of object, simple user = self._members.get(username, None) if user is None or username not in roster: return data # empty if no user data or user not in workspace portrait = self._members.portrait_for(username) if portrait is not None: data['portrait_url'] = portrait.absolute_url() propkeys = { 'fullname': 'Full name', 'email': 'Email', 'description': 'User info', 'location': 'Location', 'home_page': 'Home page', 'last_login_time': 'Last login', } restricted = self.RESTRICTED_PROPS if self._secmgr.checkPermission('Manage users', self.context): restricted = () # manager can see these properties if self._mtool.getAuthenticatedMember().getId() == username: restricted = () # user can see own restricted properties props = {} for name, title in propkeys.items(): if name in restricted: continue v = user.getProperty(name) if v: props[title] = v if props: data['properties'] = props groups = roster.groups.values() data['assignments'] = [g.title for g in groups if username in g] workspaces = self.linked_workspaces(username) if workspaces: data['workspaces'] = workspaces return data
def _members_adapter(self, members=None): return members if members is not None else ISiteMembers(self._site)