def existing_users(context): """ Look up the full user details for current workspace members """ members = IWorkspace(context).members info = [] for userid, details in members.items(): user = api.user.get(userid) if user is None: continue user = user.getUser() title = user.getProperty("fullname") or user.getId() or userid # XXX tbd, we don't know what a persons description is, yet description = _(u"Here we could have a nice status of this person") classes = description and "has-description" or "has-no-description" portal = api.portal.get() portrait = "%s/portal_memberdata/portraits/%s" % (portal.absolute_url(), userid) info.append( dict( id=userid, title=title, description=description, portrait=portrait, cls=classes, member=True, admin="Admins" in details["groups"], ) ) return info
def invitation_accepted(event): """ When an invitation is accepted, add the user to the team """ request = getRequest() storage = get_storage() if event.token_id not in storage: return ws_uid, username = storage[event.token_id] storage[event.token_id] acl_users = api.portal.get_tool("acl_users") acl_users.updateCredentials(request, request.response, username, None) catalog = api.portal.get_tool(name="portal_catalog") brain = catalog.unrestrictedSearchResults(UID=ws_uid)[0] with api.env.adopt_roles(["Manager"]): ws = IWorkspace(brain.getObject()) for name in ws.members: member = api.user.get(username=name) if member is not None: if member.getUserName() == username: api.portal.show_message(_("Oh boy, oh boy, you are already a member"), request) break else: ws.add_to_team(user=username) api.portal.show_message(_("Welcome to our family, Stranger"), request)
def test_sidebar_existing_users(self): ws = self.create_workspace() user = api.user.create(email="*****@*****.**", username="******") user_id = user.getId() self.assertNotIn(user_id, IWorkspace(ws).members, "Id already present") IWorkspace(ws).add_to_team(user=user_id) provideAdapter( SidebarSettingsMembers, (Interface, Interface), IBasicTile, name=u"sidebarSettingsMember.default", ) # Commenting out because they aren't (yet?) being used. # sidebarSettingsMembers = getMultiAdapter( # (ws, ws.REQUEST), name=u"sidebarSettingsMember.default") # existing_users = sidebarSettingsMembers.existing_users() self.assertIn( user_id, IWorkspace(ws).members, "Id not found in worskpace member Ids", )
def existing_users(context): """ Look up the full user details for current workspace members """ members = IWorkspace(context).members info = [] for userid, details in members.items(): user = api.user.get(userid) if user is None: continue user = user.getUser() title = user.getProperty('fullname') or user.getId() or userid # XXX tbd, we don't know what a persons description is, yet description = '' classes = description and 'has-description' or 'has-no-description' portal = api.portal.get() portrait = '%s/@@avatars/%s' % \ (portal.absolute_url(), userid) info.append( dict( id=userid, title=title, description=description, portrait=portrait, cls=classes, member=True, admin='Admins' in details['groups'], ) ) return info
def existing_users(context): """ Look up the full user details for current workspace members """ members = IWorkspace(context).members info = [] for userid, details in members.items(): user = api.user.get(userid) if user is None: continue user = user.getUser() title = user.getProperty('fullname') or user.getId() or userid # XXX tbd, we don't know what a persons description is, yet description = '' classes = description and 'has-description' or 'has-no-description' portal = api.portal.get() portrait = '%s/@@avatars/%s' % \ (portal.absolute_url(), userid) info.append( dict( id=userid, title=title, description=description, portrait=portrait, cls=classes, member=True, admin='Admins' in details['groups'], )) return info
def invitation_accepted(event): """ When an invitation is accepted, add the user to the team """ request = getRequest() storage = get_storage() if event.token_id not in storage: return ws_uid, username = storage[event.token_id] storage[event.token_id] acl_users = api.portal.get_tool('acl_users') acl_users.updateCredentials(request, request.response, username, None) catalog = api.portal.get_tool(name="portal_catalog") brain = catalog.unrestrictedSearchResults(UID=ws_uid)[0] with api.env.adopt_roles(["Manager"]): ws = IWorkspace(brain.getObject()) for name in ws.members: member = api.user.get(username=name) if member is not None: if member.getUserName() == username: api.portal.show_message( _('Oh boy, oh boy, you are already a member'), request, ) break else: ws.add_to_team(user=username) api.portal.show_message( _('Welcome to our family, Stranger'), request, )
def get_principal_roles(self, principal): ''' Get the description for this principalid ''' adapter = IWorkspace(self.context) if hasattr(principal, 'getGroupId'): groups = adapter.get(principal.getGroupId()).groups else: groups = adapter.get(principal.getId()).groups if 'Admins' in groups: return ['Admin'] # The policies are ordered from the less permissive to the most # permissive. We reverse them for policy in reversed(PARTICIPANT_POLICY): # BBB: code copied from the workspacefolder existing_users function # at 58c758d20a820dcb9f691168a9215bfc9741b00e # not really clear to me why we are skipping the current policy if policy != self.context.participant_policy: if policy.title() in groups: # According to the design there is at most one extra role # per user, so we go with the first one we find. This may # not be enforced in the backend though. return [PARTICIPANT_POLICY[policy]['title']] if groups == {'Guests'}: return ['Guest'] return []
def existing_users(self): """ Look up the full user details for current workspace members """ members = IWorkspace(self).members info = [] for userid, details in members.items(): user = api.user.get(userid) if user is None: continue user = user.getUser() title = user.getProperty('fullname') or user.getId() or userid # XXX tbd, we don't know what a persons description is, yet description = MessageFactory(u'Here we could have a nice status of' u' this person') classes = description and 'has-description' or 'has-no-description' portrait = pi_api.userprofile.avatar_url(userid) info.append( dict( id=userid, title=title, description=description, portrait=portrait, cls=classes, member=True, admin='Admins' in details['groups'], ) ) return info
def guest_ids(self): ''' Get the valid member ids through IWorkspace ''' adapter = IWorkspace(self.context) return [ principalid for principalid in self.member_ids if adapter.get(principalid).groups == {'Guests'} ]
def participation_policy_changed(ob, event): """ Move all the existing users to a new group """ workspace = IWorkspace(ob) old_group_name = workspace.group_for_policy(event.old_policy) old_group = api.group.get(old_group_name) for member in old_group.getAllGroupMembers(): groups = workspace.get(member.getId()).groups groups -= set([event.old_policy.title()]) groups.add(event.new_policy.title())
def test_policy_exceptions(self): self.login_as_portal_owner() workspace = api.content.create( self.workspace_container, 'ploneintranet.workspace.workspacefolder', 'workspace' ) # set default policy to producers workspace.participant_policy = 'producers' # create some members and add to workspace username = '******' username2 = 'member_username2' api.user.create(username=username, email='*****@*****.**') self.add_user_to_workspace(username, workspace) api.user.create(username=username2, email='*****@*****.**') self.add_user_to_workspace(username2, workspace) # Make an exception of username2 # by moving them to a non-default group IWorkspace(workspace).add_to_team(username2, groups={'Consume'}) group = api.group.get('Producers:' + api.content.get_uuid(workspace)) # username should be in the default group self.assertIn( api.user.get(username=username), group.getAllGroupMembers() ) # username two should *not* be in the default group self.assertNotIn( api.user.get(username=username2), group.getAllGroupMembers() ) # update default policy workspace.participant_policy = 'moderators' group = api.group.get('Moderators:' + api.content.get_uuid(workspace)) # username should have been moved to the new group self.assertIn( api.user.get(username=username), group.getAllGroupMembers() ) # username2 two should *not* be in the new default group self.assertNotIn( api.user.get(username=username2), group.getAllGroupMembers() ) # remove username2 as an exception by re-setting their groups IWorkspace(workspace).add_to_team(username2) self.assertIn( api.user.get(username=username2), group.getAllGroupMembers() )
def setUp(self): self.app = self.layer['app'] self.portal = self.layer['portal'] self.request = self.layer['request'] z2.login(self.app['acl_users'], SITE_OWNER_NAME) self.user1 = api.user.create(email='*****@*****.**', username='******', password='******') self.workspace = api.content.create(container=self.portal, type='Workspace', id='a-workspace') self.ws = IWorkspace(self.workspace)
def setUp(self): self.app = self.layer["app"] self.portal = self.layer["portal"] self.request = self.layer["request"] zope.login(self.app["acl_users"], SITE_OWNER_NAME) self.user1 = api.user.create( email="*****@*****.**", username="******", password="******" ) self.workspace = api.content.create( container=self.portal, type="Workspace", id="a-workspace" ) self.ws = IWorkspace(self.workspace)
def test_invitation_send_but_user_became_a_member_not_via_link(self): email = "*****@*****.**" username = '******' api.user.create( email=email, username=username, password='******', ) # there shouldn't be any minus admin user in workspace self.assertEqual(0, len(list(IWorkspace(self.ws).members)) - 1) request = self.make_request(username=username) form = api.content.get_view( 'invite', context=self.ws, request=request, ) form.update() data, errors = form.extractData() self.assertEqual(len(errors), 0) # no errors on the widget? self.assertEqual(form.widgets['user'].error, None) # our mock mail host received one email? self.assertEqual(len(self.mailhost.messages), 1) msg = message_from_string(self.mailhost.messages[0]) # mail is actually received by correct recipient # now lets add this user to workspace via other channels self.add_user_to_workspace(username, self.ws) self.assertEqual(msg['To'], email) body = msg.get_payload() url_match = re.search("(?P<url>http://[0-9a-z:/@-]+)(?=\n)", body) self.assertNotEqual(url_match, None) url = url_match.groupdict("url").get("url") self.mailhost.reset() import transaction transaction.commit() browser = Browser(self.app) browser.open(url) self.assertIn('userrole-authenticated', browser.contents, 'User was not authenticated after accepting token') # check that user is added to workspace self.assertEqual(1, len(list(IWorkspace(self.ws).members)) - 1) self.assertIn("Oh boy, oh boy, you are already a member", browser.contents)
def test_sidebar_existing_users(self): ws = self.create_workspace() user = api.user.create(email="*****@*****.**", username="******") user_id = user.getId() self.assertNotIn(user_id, IWorkspace(ws).members, "Id already present") IWorkspace(ws).add_to_team(user=user_id) self.assertIn( user_id, IWorkspace(ws).members, "Id not found in worskpace member Ids", )
def test_viewlet_invisible_if_user_is_member(self): self.workspace.join_policy = 'self' self.workspace.visibility = 'open' viewlet = JoinViewlet(self.folder, self.request, None, None) IWorkspace(self.workspace).add_to_team(user='******') self.login('demo') self.assertFalse(viewlet.visible())
def find_workspace(context): while hasattr(context, "context"): context = context.context for context in aq_chain(context): workspace = IWorkspace(context, None) if workspace is not None: return workspace
def test_add_admin_to_workspace(self): """ check that site admin can add team admin to the workspace """ self.login_as_portal_owner() ws = self._create_unadapted_workspace() user = self._create_user() groups = api.group.get_groups() group_names = [x.getName() for x in groups] group_name = 'Admins:%s' % (api.content.get_uuid(ws)) self.assertIn(group_name, group_names) workspace = IWorkspace(ws) workspace.add_to_team(user=user.getId(), groups=set([u"Admins"])) portal = api.portal.get() pgroups = portal.portal_groups.getGroupById(group_name) member_ids = pgroups.getGroup().getMemberIds() self.assertIn(user.getId(), member_ids)
def existing_users(self): members = IWorkspace(self.context).members info = [] for userid, details in members.items(): user = api.user.get(userid).getUser() title = user.getProperty('fullname') or user.getId() or userid info.append( dict( id=userid, title=title, member=True, admin='Admins' in details['groups'], ) ) return info
def __call__(self): q = self.request.get('q', '').lower() groups = self.get_groups() group_details = [] ws = IWorkspace(self.context) for group in groups: groupid = group.getId() # XXX Filter out groups representing workspace roles. Review # whether we need/want this and/or can do it more efficiently. if (groupid == self.context.id or # don't add group to itself group.getProperty('state') == 'secret' or groupid.partition(':')[0] in ws.available_groups): continue title = group.getProperty('title') or groupid email = group.getProperty('email') if email: title = '%s <%s>' % (title, email) description = group.getProperty('description') or '' if q in title.lower() or q in description.lower(): group_details.append({ 'text': title, 'id': groupid, }) return dumps(group_details)
def test_acquired_roles_from_policy_settings(self): self.login_as_portal_owner() policy = "moderators" self.workspace.participant_policy = policy ws = IWorkspace(self.workspace) ws.add_to_team(user=self.user.getUserName()) roles = ws.available_groups.get(policy.title()) self.request.form = {'form.button.Search': 'Search', 'search_term': 'demo'} view = SharingView(self.workspace, self.request) results = view.user_search_results() self.assertEqual(len(results), 1) self.assertTrue( all([results[0]["roles"][role] == "acquired" for role in roles]), "Acquired roles were not set correctly")
def _getWorkspace(self, uid): catalog = getToolByName(self, 'portal_catalog') res = catalog.unrestrictedSearchResults( object_provides=WORKSPACE_INTERFACE, UID=uid) if not res: return return IWorkspace(res[0]._unrestrictedGetObject())
def _create_workspace(self): """ returns adapted workspace folder""" workspace_folder = api.content.create( self.workspace_container, 'ploneintranet.workspace.workspacefolder', 'example-workspace', title='Welcome to my workspace') return IWorkspace(workspace_folder)
def setUp(self): self.app = self.layer["app"] self.portal = self.layer["portal"] self.request = self.layer["request"] z2.login(self.app["acl_users"], SITE_OWNER_NAME) self.user1 = api.user.create(email="*****@*****.**", username="******", password="******") self.workspace = api.content.create(container=self.portal, type="Workspace", id="a-workspace") self.ws = IWorkspace(self.workspace)
def test_member_is_added_to_user_title_if_user_is_a_member(self): self.login_as_portal_owner() IWorkspace(self.workspace).add_to_team(user=self.user.getUserName()) self.request.form = { 'form.button.Search': 'Search', 'search_term': 'demo' } view = SharingView(self.workspace, self.request) self.assertIn('%s [member]' % (self.user.getUserName(), ), view())
def test_acquired_roles_from_policy_settings(self): self.login_as_portal_owner() policy = "moderators" self.workspace.participant_policy = policy ws = IWorkspace(self.workspace) ws.add_to_team(user=self.user.getUserName()) roles = ws.available_groups.get(policy.title()) self.request.form = { 'form.button.Search': 'Search', 'search_term': 'demo' } view = SharingView(self.workspace, self.request) results = view.user_search_results() self.assertEqual(len(results), 1) self.assertTrue( all([results[0]["roles"][role] == "acquired" for role in roles]), "Acquired roles were not set correctly")
def __call__(self): if not self.context.join_policy == "self": msg = _(u"Workspace join policy doesn't allow self join") raise Unauthorized(msg) field = "button.join" req_method = self.request.method.lower() if req_method == "post" and field in self.request.form: user = api.user.get_current() workspace = IWorkspace(self.context) workspace.add_to_team(user=user.getId()) msg = _(u"You are a member of this workspace now") api.portal.show_message(message=_(msg), request=self.request) referer = self.request.get("HTTP_REFERER", "").strip() if not referer: referer = self.context.absolute_url() return self.request.response.redirect(referer)
def invitation_accepted(event): """ When an invitation is accepted, add the user to the team. This apparently is NOT a ploneintranet.invitations invitation, but by ploneintranet.workspace.browser.forms.InviteForm. """ request = getRequest() storage = get_storage() if event.token_id not in storage: return ws_uid, userid = storage[event.token_id] # in a email_as_login setting (see #1043) # .userid == .username but .username != .getUserName() ... :-( username = api.user.get(userid=userid).getUserName() acl_users = api.portal.get_tool('acl_users') acl_users.updateCredentials( request, request.response, username, # the login, not the userid None ) catalog = api.portal.get_tool(name="portal_catalog") brain = catalog.unrestrictedSearchResults(UID=ws_uid)[0] with api.env.adopt_roles(["Manager"]): ws = IWorkspace(brain.getObject()) # collective.workspace .members returns userid iterator for member_id in ws.members: # don't clobber userid variable member = api.user.get(userid=member_id) if member is not None: if member.getId() == userid: api.portal.show_message( _('Oh boy, oh boy, you are already a member'), request, ) break else: # 'user' in this API is actually userid ws.add_to_team(user=userid) api.portal.show_message( _('Welcome to our family, Stranger'), request, )
def test_user_redirected_if_method_get(self): self.open_workspace() self.request.method = 'GET' self.request.form = {'button.join': True} self.request['HTTP_REFERER'] = 'someurl' self.login('demo') view = JoinView(self.workspace, self.request) response = view() self.assertEqual('someurl', response) self.assertNotIn('demo', IWorkspace(self.workspace).members)
def test_user_deletion_from_site_removes_from_workspace(self): username = "******" api.user.create( email="*****@*****.**", username=username, password="******", ) # there shouldn't be any minus admin user in workspace self.assertEqual(0, len(list(IWorkspace(self.ws).members)) - 1) # lets add one user self.add_user_to_workspace(username, self.ws) self.assertEqual(1, len(list(IWorkspace(self.ws).members)) - 1) # now lets remove a user from the site api.user.delete(username) # and this user should be gone from workspace as well self.assertEqual(0, len(list(IWorkspace(self.ws).members)) - 1)
def test_add_admin_to_workspace(self): """ check that site admin can add team admin to the workspace """ self.login_as_portal_owner() ws = self.create_unadapted_workspace() user = self.create_user() groups = api.group.get_groups() group_names = [x.getName() for x in groups] group_name = 'Admins:%s' % (api.content.get_uuid(ws)) self.assertIn( group_name, group_names ) workspace = IWorkspace(ws) workspace.add_to_team(user=user.getId(), groups=set([u"Admins"])) portal = api.portal.get() pgroups = portal.portal_groups.getGroupById(group_name) member_ids = pgroups.getGroup().getMemberIds() self.assertIn(user.getId(), member_ids)
def participant_policy(self, value): """ Changing participation policy fires a "ParticipationPolicyChanged" event """ old_policy = self.participant_policy new_policy = value self._participant_policy = new_policy IWorkspace(self).update_participant_policy_groups( old_policy, new_policy, ) notify(ParticipationPolicyChangedEvent(self, old_policy, new_policy))
def workspace_added(ob, event): """ when a workspace is created, we add the creator to the admin group. We then setup our placeful workflow """ is_case = ICase.providedBy(ob) preserve_template_ownership = api.portal.get_registry_record( 'ploneintranet.workspace.preserve_template_ownership', default=False, ) userid = api.user.get_current().id # If not stated otherwise through the registry record: # ploneintranet.workspace.preserve_template_ownership # whoever creates the workspace should be added as an Admin # When copying a template, that is the current user # (not the one who created the original template) if (not is_case) or (not preserve_template_ownership): ob.setCreators([userid]) IWorkspace(ob).add_to_team( user=userid, groups=set(['Admins']), ) # During workspace creation, various functions # are called (renaming / workflow transitions) which do # low-level AccessControl checks. # Unfortunately these checks never re-ask PAS for a user's roles # or groups during a request, so we have to manually re-initialise # the security context for the current user. # ref: https://github.com/ploneintranet/ploneintranet/pull/438 _reset_security_context(userid, ob.REQUEST) if is_case: """Case Workspaces have their own custom workflows """ return # Configure our placeful workflow cmfpw = 'CMFPlacefulWorkflow' try: ob.manage_addProduct[cmfpw].manage_addWorkflowPolicyConfig() except BadRequest: # 'The id ".wf_policy_config" is invalid - it is already in use.' # copying a template workspace which already has a policy defined return # Set the policy for the config pc = getattr(ob, WorkflowPolicyConfig_id) pc.setPolicyIn('') pc.setPolicyBelow('ploneintranet_policy')
def user_search_results(self): """ Add [member] to a user title if user is a member of current workspace """ results = super(SharingView, self).user_search_results() ws = IWorkspace(self.context) roles_mapping = ws.available_groups roles = roles_mapping.get(self.context.participant_policy.title()) for result in results: if result["id"] in ws.members: groups = ws.get(result["id"]).groups for role in roles: result["roles"][role] = "acquired" if "Admins" in groups: title = "administrator" result["roles"]["TeamManager"] = "acquired" else: title = "member" result["title"] = "%s [%s]" % (result["title"], title) return results
def test_administrator_is_added_to_administrator(self): """ Test that [administrator] is added to the workspace administrator """ self.login_as_portal_owner() IWorkspace(self.workspace).add_to_team(user=self.user.getId(), groups=set(["Admins"])) self.request.form = { 'form.button.Search': 'Search', 'search_term': 'demo' } view = SharingView(self.workspace, self.request) self.assertIn('%s [administrator]' % (self.user.getId(), ), view()) self.assertNotIn("%s [member]" % (self.user.getId(), ), view())
def execute_batch_function(self): if not self.can_manage_roster(): msg = _(u'You do not have permission to change the workspace ' u'policy') raise Unauthorized(msg) form = self.request.form user_ids = form.get('user_id') if not user_ids: return if isinstance(user_ids, basestring): user_ids = user_ids.split(',') ws = self.workspace() batch_function = form.get('batch-function') if batch_function == 'add': for user_id in user_ids: IWorkspace(ws).add_to_team(user=user_id) msg = _(u'Member(s) added') msg_type = 'success' elif batch_function == 'remove': for user_id in user_ids: IWorkspace(ws).remove_from_team(user=user_id) msg = _(u'Member(s) removed') msg_type = 'success' elif batch_function == 'role': role = self.request.get('role') groups = role and {role} or None for user_id in user_ids: IWorkspace(ws).add_to_team(user=user_id, groups=groups) msg = _(u'Role updated') msg_type = 'success' else: msg = _(u'Unknown function') msg_type = 'error' api.portal.show_message(msg, self.request, msg_type) notify(WorkspaceRosterChangedEvent(self.context))
def test_update_users_add_member(self): view = getMultiAdapter((self.workspace, self.request), name='edit-roster') settings = [ { 'id': 'wsmember2', 'member': True, }, ] view.update_users(settings) members = IWorkspace(self.workspace).members self.assertIn('wsmember2', members)
def test_update_users_remove_admin(self): """ Remove admin role from workspace as manager """ view = getMultiAdapter((self.workspace, self.request), name='edit-roster') settings = [{ 'id': 'wsadmin', 'member': True, 'admin': False, }, { 'id': 'wsmember', 'member': True, }] view.update_users(settings) members = IWorkspace(self.workspace).members self.assertIn('wsadmin', members) self.assertNotIn( 'Admins', IWorkspace(self.workspace).get('wsadmin').groups, )
def update_users(self, entries): """Update user properties on the roster """ ws = IWorkspace(self.context) members = ws.members # check user permissions against join policy join_policy = self.context.join_policy if (join_policy == "admin" and not checkPermission( "ploneintranet.workspace: Manage workspace", self.context)): raise Unauthorized("You are not allowed to add users here") for entry in entries: id = entry.get('id') is_member = bool(entry.get('member')) is_admin = bool(entry.get('admin')) # Existing members if id in members: member = members[id] if not is_member: if checkPermission( "ploneintranet.workspace: Manage workspace", self.context): ws.membership_factory(ws, member).remove_from_team() else: raise Unauthorized( "Only team managers can remove members") elif not is_admin: ws.membership_factory(ws, member).groups -= {'Admins'} else: ws.membership_factory(ws, member).groups |= {'Admins'} # New members elif id not in members and (is_member or is_admin): groups = set() if is_admin: groups.add('Admins') ws.add_to_team(user=id, groups=groups)
def handleApply(self, action): data = self.extractData()[0] ws = IWorkspace(self.context) other_ws_id = data.get("workspace") other_ws = IWorkspace(api.content.get(UID=other_ws_id)) move = data.get("move", False) removable = [] for member in ws.members: user = api.user.get(username=member) if user is not None: user_id = user.getId() other_ws.add_to_team(user=user_id) removable.append(member) if move: func = lambda member: ws.membership_factory( ws, {"user": member}).remove_from_team() map(func, removable) self.updateWidgets() self.status = "Members transfered."
def setUp(self): self.app = self.layer['app'] self.portal = self.layer['portal'] self.request = self.layer['request'] z2.login(self.app['acl_users'], SITE_OWNER_NAME) self.user1 = api.user.create( email='*****@*****.**', username='******', password='******' ) self.workspace = api.content.create( container=self.portal, type='Workspace', id='a-workspace' ) self.ws = IWorkspace(self.workspace)
def update_users(self, entries): """Update user properties on the roster """ ws = IWorkspace(self.context) members = ws.members # check user permissions against join policy join_policy = self.context.join_policy if (join_policy == "admin" and not checkPermission( "collective.workspace: Manage roster", self.context)): raise Unauthorized("You are not allowed to add users here") for entry in entries: id = entry.get('id') is_member = bool(entry.get('member')) is_admin = bool(entry.get('admin')) # Existing members if id in members: member = members[id] if not is_member: if checkPermission( "ploneintranet.workspace: Manage workspace", self.context): ws.membership_factory(ws, member).remove_from_team() else: raise Unauthorized( "Only team managers can remove members") elif not is_admin: ws.membership_factory(ws, member).groups -= {'Admins'} else: ws.membership_factory(ws, member).groups |= {'Admins'} # New members elif id not in members and (is_member or is_admin): groups = set() if is_admin: groups.add('Admins') ws.add_to_team(user=id, groups=groups)
class TestWorkspace(unittest.TestCase): layer = COLLECTIVE_WORKSPACE_INTEGRATION_TESTING def setUp(self): self.app = self.layer["app"] self.portal = self.layer["portal"] self.request = self.layer["request"] z2.login(self.app["acl_users"], SITE_OWNER_NAME) self.user1 = api.user.create(email="*****@*****.**", username="******", password="******") self.workspace = api.content.create(container=self.portal, type="Workspace", id="a-workspace") self.ws = IWorkspace(self.workspace) def test_add_to_team(self): self.ws.add_to_team(user=self.user1.getId()) self.assertIn(self.user1.getId(), list(self.ws.members)) def test_remove_from_team(self): self.ws.add_to_team(user=self.user1.getId()) self.ws.remove_from_team(user=self.user1.getId()) self.assertNotIn(self.user1.getId(), list(self.ws.members))
class TestWorkspace(unittest.TestCase): layer = COLLECTIVE_WORKSPACE_INTEGRATION_TESTING def setUp(self): self.app = self.layer['app'] self.portal = self.layer['portal'] self.request = self.layer['request'] z2.login(self.app['acl_users'], SITE_OWNER_NAME) self.user1 = api.user.create( email='*****@*****.**', username='******', password='******' ) self.workspace = api.content.create( container=self.portal, type='Workspace', id='a-workspace' ) self.ws = IWorkspace(self.workspace) def _get_roles_in_workspace(self): pmt = api.portal.get_tool('portal_membership') member = pmt.getMemberById(self.user1.getId()) return member.getRolesInContext(self.workspace) def test_adding_workspace_creates_groups(self): group = self.portal.portal_groups.getGroupById( 'Admins:' + self.workspace.UID()) self.assertIsNotNone(group) def test_renaming_workspace_updates_group_titles(self): self.workspace.setTitle('new title') from zope.lifecycleevent import modified modified(self.workspace) group = self.portal.portal_groups.getGroupById( 'Admins:' + self.workspace.UID()) self.assertEqual(group.getProperty('title'), 'Admins: new title') def test_removing_workspace_removes_groups(self): self.portal.manage_delObjects(['a-workspace']) group = self.portal.portal_groups.getGroupById( 'Admins:' + self.workspace.UID()) self.assertIsNone(group) def test_add_to_team(self): self.ws.add_to_team( user=self.user1.getId() ) self.assertIn(self.user1.getId(), list(self.ws.members)) def test_adding_team_member_updates_groups(self): self.ws.add_to_team( user=self.user1.getId(), groups=(u'Admins',), ) self.assertIn( self.user1.getId(), self.portal.portal_groups.getGroupMembers( 'Members:' + self.workspace.UID()), ) self.assertIn( self.user1.getId(), self.portal.portal_groups.getGroupMembers( 'Admins:' + self.workspace.UID()), ) def test_updating_team_member_updates_groups(self): self.ws.add_to_team( user=self.user1.getId() ) self.ws[self.user1.getId()].update({'groups': set([u'Admins'])}) self.assertIn( self.user1.getId(), self.portal.portal_groups.getGroupMembers( 'Members:' + self.workspace.UID()), ) self.assertIn( self.user1.getId(), self.portal.portal_groups.getGroupMembers( 'Admins:' + self.workspace.UID()), ) def test_direct_set_of_membership_property_is_blocked(self): self.ws.add_to_team( user=self.user1.getId() ) try: self.ws[self.user1.getId()].position = u'Tester' except Exception as e: self.assertEqual( str(e), 'Setting membership properties directly is not supported. ' 'Use the `update` method instead.' ) else: self.fail('Expected exception') def test_local_role_team_member(self): self.ws.add_to_team( user=self.user1.getId() ) self.assertIn('TeamMember', self._get_roles_in_workspace()) def test_remove_from_team(self): self.ws.add_to_team( user=self.user1.getId() ) self.ws.remove_from_team( user=self.user1.getId() ) self.assertNotIn(self.user1.getId(), list(self.ws.members)) def test_removing_team_member_updates_groups(self): self.ws.add_to_team( user=self.user1.getId(), groups=(u'Admins',), ) self.ws.remove_from_team( user=self.user1.getId() ) self.assertNotIn( self.user1.getId(), self.portal.portal_groups.getGroupMembers( 'Members:' + self.workspace.UID()), ) self.assertNotIn( self.user1.getId(), self.portal.portal_groups.getGroupMembers( 'Admins:' + self.workspace.UID()), ) def test_reparent_team_member(self): self.ws.add_to_team( user=self.user1.getId(), groups=(u'Admins',), ) user2 = api.user.create( email='*****@*****.**', username='******', password='******' ) self.ws[self.user1.getId()].update({'user': user2.getId()}) self.assertNotIn(self.user1.getId(), self.workspace._team) self.assertIn(user2.getId(), self.workspace._team) self.assertEqual(self.ws[user2.getId()].user, user2.getId()) self.assertNotIn( self.user1.getId(), self.portal.portal_groups.getGroupMembers( 'Admins:' + self.workspace.UID()), ) self.assertIn( user2.getId(), self.portal.portal_groups.getGroupMembers( 'Admins:' + self.workspace.UID()), ) def test_removing_user_removes_workspace_memberships(self): userid = self.user1.getId() self.ws.add_to_team(user=userid) self.assertIn(userid, self.ws.members) api.user.delete(userid) self.assertNotIn(userid, self.ws.members) self.assertNotIn( userid, self.portal.portal_groups.getGroupMembers( 'Members:' + self.workspace.UID()), ) def test_copying_workspace_clears_roster(self): cookie = self.portal.manage_copyObjects(ids=('a-workspace',)) self.portal.manage_pasteObjects(cookie) self.assertTrue('copy_of_a-workspace' in self.portal) workspace = self.portal['copy_of_a-workspace'] self.assertEqual(len(workspace._team), 0) self.assertEqual(workspace._counters['members'](), 0) def test_add_guest_to_team(self): self.ws.add_to_team( user=self.user1.getId(), groups=['Guests'] ) self.assertIn(self.user1.getId(), list(self.ws.members)) def test_guest_has_no_team_member_role(self): self.ws.add_to_team( user=self.user1.getId(), groups=['Guests'] ) pmt = api.portal.get_tool('portal_membership') member = pmt.getMemberById(self.user1.getId()) roles = member.getRolesInContext(self.workspace) self.assertIn('TeamGuest', roles) self.assertNotIn('TeamMember', roles) def test_creating_and_removing_plone_groups_is_possible(self): test_group_id = 'My workspace testers' self.assertIsNone(api.group.get(test_group_id)) api.group.create(test_group_id) group = api.group.get(test_group_id) self.assertEquals(group.getId(), test_group_id) api.group.delete(test_group_id) self.assertIsNone(api.group.get(test_group_id)) def test_update_membership_groups(self): ''' Test that calling _update_groups will always add the Members group, unless the user is also in the Guests group ''' self.assertNotIn('TeamMember', self._get_roles_in_workspace()) # Adding the user to the workspace will grant the TeamMember role membership = self.ws.add_to_team(user=self.user1.getId()) self.assertIn('TeamMember', self._get_roles_in_workspace()) # groups should be untouched old = set() new = set() membership._update_groups(old, new) self.assertIn('TeamMember', self._get_roles_in_workspace()) # groups should be untouched because user is already a member old = set() new = set(['Members']) membership._update_groups(old, new) self.assertIn('TeamMember', self._get_roles_in_workspace()) # Removing the automatic group will not actually remove it # because it is an automatic group old = set(['Members']) new = set() membership._update_groups(old, new) self.assertIn('TeamMember', self._get_roles_in_workspace()) # Removing the automatic group will have no effect old = set(['Members']) new = set() membership._update_groups(old, new) self.assertIn('TeamMember', self._get_roles_in_workspace()) # Adding the user to the Guests group will remove it from the Members # because the condition will not be satisifed old = set() new = set(['Guests']) membership._update_groups(old, new) self.assertIn('TeamGuest', self._get_roles_in_workspace()) self.assertNotIn('TeamMember', self._get_roles_in_workspace()) def test_membership_remove_all_groups(self): ''' Test that calling _remove_all_groups does so ''' self.assertNotIn('TeamMember', self._get_roles_in_workspace()) # Adding the user to the workspace will grant the TeamMember role membership = self.ws.add_to_team(user=self.user1.getId()) self.assertIn('TeamMember', self._get_roles_in_workspace()) # groups should be removed membership._remove_all_groups() self.assertNotIn('TeamMember', self._get_roles_in_workspace())
class TeamMemberEditForm(AutoExtensibleForm, EditForm): def __init__(self, context, request): self.context = context self.request = request self.workspace = IWorkspace(self.context) key = None def publishTraverse(self, request, name): self.key = name return self @lazy_property def schema(self): return self.workspace.membership_schema def updateFields(self): super(TeamMemberEditForm, self).updateFields() # don't show the user field if we are editing if self.key: del self.fields['user'] @lazy_property def ignoreContext(self): return not bool(self.key) @lazy_property def label(self): if self.key: return self.getContent()._title else: return _(u'Add Person to Roster') @lazy_property def _content(self): if not self.key: return self.context workspace = self.workspace memberdata = workspace.members[self.key] return workspace.membership_factory(workspace, memberdata) def getContent(self): return self._content def validateInvariants(self, membership): pass @button.buttonAndHandler(_(u'Save')) def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return status = _(u'Changes saved') if self.key: membership = self.getContent() membership.update(data) else: # Add new roster member membership = self.workspace.add_to_team(**data) status = _(u'User added') try: self.validateInvariants(membership) except ActionExecutionError: # make sure above changes won't be persisted transaction.abort() raise self._finished = True IStatusMessage(self.request).addStatusMessage(status, 'info') @property def can_remove(self): return self.key @button.buttonAndHandler( _(u'Remove'), condition=lambda self: self.can_remove) def handleRemove(self, action): membership = self.getContent() membership.remove_from_team() self._finished = True IStatusMessage(self.request).addStatusMessage( _(u"User removed"), "info") _finished = False def render(self): if self._finished: return ' ' return super(TeamMemberEditForm, self).render()
def existing_users(self): """ Look up the full user details for current workspace members """ members = IWorkspace(self).members info = [] for user_or_group_id, details in members.items(): user = api.user.get(user_or_group_id) if user is not None: user = user.getUser() title = (user.getProperty('fullname') or user.getId() or user_or_group_id) # XXX tbd, we don't know what a persons description is, yet description = '' classes = 'user ' + (description and 'has-description' or 'has-no-description') portrait = pi_api.userprofile.avatar_url(user_or_group_id) else: group = api.group.get(user_or_group_id) if group is None: continue title = (group.getProperty('title') or group.getId() or user_or_group_id) description = _( u"number_of_members", default=u'${no_members} Members', mapping={ u'no_members': len(group.getAllGroupMemberIds())}) classes = 'user-group has-description' portrait = '' # User's 'role' is any group they are a member of # that is not the default participation policy group # (including Admins group) role = None groups = details['groups'] if 'Admins' in groups: role = 'Admin' for policy in PARTICIPANT_POLICY: if policy == self.participant_policy: continue if policy.title() in groups: role = PARTICIPANT_POLICY[policy]['title'] # According to the design there is at most one extra role # per user, so we go with the first one we find. This may # not be enforced in the backend though. break if role: classes += ' has-label' info.append( dict( id=user_or_group_id, title=title, description=description, portrait=portrait, cls=classes, member=True, admin='Admins' in details['groups'], role=role, ) ) return info
class TeamMemberEditForm(AutoExtensibleForm, EditForm): def __init__(self, context, request): self.context = context self.request = request self.workspace = IWorkspace(self.context) user_id = None def publishTraverse(self, request, name): self.user_id = name return self @lazy_property def schema(self): return self.workspace.membership_schema def updateFields(self): super(TeamMemberEditForm, self).updateFields() # don't show the user field if we are editing if self.user_id: del self.fields['user'] @lazy_property def ignoreContext(self): return not bool(self.user_id) @lazy_property def label(self): if self.user_id: mtool = getToolByName(self.context, 'portal_membership') member = mtool.getMemberById(self.user_id) if member is not None: return member.getProperty('fullname') or self.user_id else: return self.user_id else: return u'Add Person to Roster' @lazy_property def _content(self): if not self.user_id: return self.context workspace = self.workspace memberdata = workspace.members[self.user_id] return workspace.membership_factory(workspace, memberdata) def getContent(self): return self._content def validateInvariants(self, membership): pass @button.buttonAndHandler(u'Save') def handleSave(self, action): data, errors = self.extractData() if errors: return if self.user_id: membership = self.getContent() membership.update(data) else: # Add new roster member membership = self.workspace.add_to_team(**data) try: self.validateInvariants(membership) except ActionExecutionError: # make sure above changes won't be persisted transaction.abort() raise self._finished = True @property def can_remove(self): return self.user_id @button.buttonAndHandler(u'Remove', condition=lambda self: self.can_remove) def handleRemove(self, action): membership = self.getContent() membership.remove_from_team() self._finished = True _finished = False def render(self): if self._finished: return ' ' return super(TeamMemberEditForm, self).render()
def __init__(self, context, request): self.context = context self.request = request self.workspace = IWorkspace(self.context)