def user_workspaces(username, context=None): """ 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. """ suffix = '-viewers' site = getSite() context = context or site # get all PAS groups for workspaces contained within context: all_workspaces = get_workspaces(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 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 handle_workspace_pasted(context, event, original_path): """handle IObjectAddedEvent after a copy/paste opertion""" create_workspace_groups_roles(context) for workspace in get_workspaces(context): create_workspace_groups_roles(workspace)
def _update_grid(self, *args, **kwargs): groupmeta = self.groups() ## create a mapping of named (by group) queues for each action ## each mapping will maintain a set of usernames per group ## for removal, addition: _unassign = dict((info['groupid'], set()) for info in groupmeta) _add = dict((info['groupid'], set()) for info in groupmeta) ## get a list of known usernames to form at time of its render ## -- this avoids race condition when roster changes do to a member ## being added in the meantime; however, if a member is deleted, ## between form render and form submit, we need to handle that ## by getting an intersection of roster for workspace and the ## set of all usernames known to the form. ## (the form template is responsible to render a hidden input ## for each username with a name containing the username). known = set(self.roster.keys()) managed = set(k.replace('managegroups-', '') for k in self.form.keys() if k.startswith('managegroups-')) managed = managed.intersection(known) ## iterate through each known group (column in grid): for info in groupmeta: groupid = info['groupid'] group = self.roster.groups[groupid] form_group_users = set(k.split('/')[1] for k, v in self.form.items() if k.startswith('group-%s/' % groupid)) for username in managed: if username not in form_group_users and username in group: # was in group existing, but ommitted/unchecked in form # for this username -- mark for removal. _unassign[groupid].add(username) elif username in form_group_users and username not in group: # not yet in existing group, but specified/checked # in form, so we need to mark for adding _add[groupid].add(username) groups = self.roster.groups.values() for groupid, deletions in _unassign.items(): group = self.roster.groups[groupid] for username in deletions: if username in group: existing_user_groups = [g for g in groups if username in g] if username == self.authuser and groupid == 'managers': msg = u'Managers cannot remove manager role for '\ u'themselves (%s)' % (username,) self.status.addStatusMessage(msg, type='warning') continue if groupid == 'viewers' and len(existing_user_groups) > 1: other_deletions = reduce( _true, [username in v for k, v in _unassign.items() if k != 'viewers'], ) if not other_deletions: # danger, danger: user in non-viewers group # not also marked for deletion msg = u'User %s cannot be removed from '\ u'Viewers group when also member '\ u'of other groups. To remove '\ u'use please uncheck all group '\ u'assignments in the grid.' % (username,) self.status.addStatusMessage( msg, type="warning", ) continue group.unassign(username) rmsg = u'%s removed from %s group for workspace (%s).' msg = rmsg % ( username, group.title, self.title, ) if groupid == 'viewers': # a total removal from workspace implies removal # of all assignments from contained workspaces. self.status.addStatusMessage(msg, type='info') self._log(msg, level=logging.INFO) for workspace in get_workspaces(self.context): roster = WorkspaceRoster(workspace) if username in roster.groups['viewers']: for group in roster.groups.values(): if username in group: group.unassign(username) for groupid, additions in _add.items(): group = self.roster.groups[groupid] for username in additions: if username not in group: group.add(username) msg = u'%s added to %s group for workspace (%s).' % ( username, group.title, self.title, ) self.status.addStatusMessage(msg, type='info') self._log(msg, level=logging.INFO) self.refresh()