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",
        )
Exemple #2
0
    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()
        )
Exemple #3
0
    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",
        )
Exemple #5
0
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
Exemple #6
0
    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)
Exemple #7
0
 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())
Exemple #8
0
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
Exemple #9
0
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,
            )
Exemple #10
0
    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 []
Exemple #11
0
 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'}
     ]
Exemple #12
0
    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())
Exemple #13
0
 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)
Exemple #14
0
 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())
Exemple #15
0
 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)
Exemple #16
0
    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)
Exemple #17
0
 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)
Exemple #19
0
 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))
Exemple #20
0
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')
Exemple #21
0
 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())
Exemple #22
0
    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."
Exemple #23
0
    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,
        )
Exemple #24
0
    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))
Exemple #25
0
    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)
Exemple #26
0
    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))
Exemple #27
0
    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)
Exemple #28
0
    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)
Exemple #29
0
    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)