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 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 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 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 __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_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 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 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 _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 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_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 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 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 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 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 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 userid in ws.members: user = api.user.get(userid=userid) if user is not None: user_id = user.getId() other_ws.add_to_team(user=user_id) removable.append(userid) if move: for userid in removable: factory = ws.membership_factory(ws, {"user": userid}) factory.remove_from_team() self.updateWidgets() self.status = "Members transfered."
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 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 update_case_access(self): """ Iterate over all tasks inside the case. - If a member is assigned to a task and the task in the current milestone: Grant Guest access, if the user is not a regular member of the Case - If a member has Guest access, but is not an assignee in any task of the current milestone: Remove Guest access """ # First of all we take the set of the todo assignees pc = api.portal.get_tool('portal_catalog') review_state = api.content.get_state(self) brains = pc.unrestrictedSearchResults( path='/'.join(self.getPhysicalPath()), portal_type='todo', ) objs = filter( lambda obj: obj.assignee and obj.milestone == review_state, (brain._unrestrictedGetObject() for brain in brains)) assignees = {obj.assignee for obj in objs} # now we make a partition of the user associated to this context existing_users = self.existing_users() existing_guests = set([]) non_guests = set([]) for user in existing_users: if user.get('role') == 'Guest': existing_guests.add(user['id']) else: non_guests.add(user['id']) # We find out which assignees are guests entitled_guests = assignees.difference(non_guests) workspace = IWorkspace(self) # We have some stale guests that should be removed from this context stale_guests = existing_guests.difference(entitled_guests) for user_id in stale_guests: workspace.remove_from_team(user_id) # We have some new guests that should be added to this context new_guests = entitled_guests.difference(existing_guests) for user_id in new_guests: workspace.add_to_team(user_id, groups=['Guests']) # If roles were changed, throw the required event if len(stale_guests) + len(new_guests): notify(WorkspaceRosterChangedEvent(self))
def _iterWorkspaces(self, userid=None): workspaces = IAnnotations(self.REQUEST).get(('workspaces', userid)) if workspaces is None: catalog = getToolByName(self, 'portal_catalog') query = {'object_provides': WORKSPACE_INTERFACE} if userid: query['workspace_members'] = userid workspaces = [ IWorkspace(b._unrestrictedGetObject()) for b in catalog.unrestrictedSearchResults(query) ] IAnnotations(self.REQUEST)[('workspaces', userid)] = workspaces return iter(workspaces)
def test_edit_roster_form(self): self.browser_login_as_site_administrator() self.browser.open('%s/@@edit-roster' % self.workspace.absolute_url()) self.browser.getControl(name='search_term').value = 'wsmember' self.browser.getControl(name='form.button.SearchUsers').click() # make sure both admin checkboxes are selected self.browser.getControl(name='entries.admin:records').value = [ '1', '1' ] self.browser.getControl(name='form.button.Save').click() # wsmember should now be an admin self.assertIn('Admins', IWorkspace(self.workspace).get('wsmember').groups)
def test_update_users_remove_member(self): self.login('wsadmin') view = getMultiAdapter((self.workspace, self.request), name='edit-roster') settings = [ { 'id': 'wsmember', 'member': False, }, ] view.update_users(settings) members = IWorkspace(self.workspace).members self.assertNotIn('wsmember', members)
def create_caseworkspaces(caseworkspaces, container='workspaces', force=False, workflow_policy='case_workflow', portal_type='ploneintranet.workspace.case'): portal = api.portal.get() pwft = api.portal.get_tool("portal_placeful_workflow") if container not in portal: ws_folder = api.content.create( container=portal, type='ploneintranet.workspace.workspacecontainer', title='Workspaces') api.content.transition(ws_folder, 'publish') else: ws_folder = portal[container] if not force and ('ploneintranet.workspace.case' in [x.portal_type for x in ws_folder.objectValues()]): log.info("caseworkspaces already setup. skipping for speed.") return for w in caseworkspaces: contents = w.pop('contents', None) members = w.pop('members', []) state = w.pop('state', None) try: caseworkspace = api.content.create(container=ws_folder, type=portal_type, **w) except: log.exception( 'Error creating %s in %r', portal_type, ws_folder, ) continue caseworkspace.manage_addProduct[ 'CMFPlacefulWorkflow'].manage_addWorkflowPolicyConfig() wfconfig = pwft.getWorkflowPolicyConfig(caseworkspace) wfconfig.setPolicyIn(workflow_policy) if contents is not None: create_ws_content(caseworkspace, contents) for (m, groups) in members.items(): IWorkspace(caseworkspace).add_to_team(user=m, groups=set(groups)) if state is not None: api.content.transition(caseworkspace, to_state=state)