Skip to content

Commit

Permalink
added ability to copy/move users between workspaces for site admin
Browse files Browse the repository at this point in the history
  • Loading branch information
Rapolas K committed May 23, 2014
1 parent 80cfc46 commit 6299f99
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/ploneintranet/workspace/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,11 @@
permission="cmf.ModifyPortalContent"
/>

<browser:page
name="transfer"
for="ploneintranet.workspace.workspacefolder.IWorkspaceFolder"
class=".forms.TransferMembershipForm"
permission="cmf.ModifyPortalContent"
/>

</configure>
67 changes: 67 additions & 0 deletions src/ploneintranet/workspace/browser/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from collective.workspace.interfaces import IWorkspace
from plone import api
from plone.directives import form
from z3c.form import button
from zope import schema
from zope.interface import directlyProvides
from zope.schema.interfaces import IContextSourceBinder
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm

from ploneintranet.workspace import MessageFactory as _
Expand Down Expand Up @@ -78,3 +82,66 @@ def updateWidgets(self):
self.widgets["external_visibility"].value = ws.external_visibility
self.widgets["join_policy"].value = ws.join_policy
self.widgets["participant_policy"].value = ws.participant_policy


def workspaces_provider(context):
catalog = api.portal.get_tool(name="portal_catalog")
workspaces = catalog(portal_type="ploneintranet.workspace.workspacefolder")
current = api.content.get_uuid(context)

terms = []
for ws in workspaces:
if current != ws["UID"]:
terms.append(SimpleVocabulary.createTerm(
ws["UID"], ws["UID"], ws["Title"]))

return SimpleVocabulary(terms)

directlyProvides(workspaces_provider, IContextSourceBinder)


class ITransferMembershipForm(form.Schema):

workspace = schema.Choice(
title=_(u"Select workspace"),
source=workspaces_provider,
)

move = schema.Bool(
title=_(u"Move"),
description=_(u"If checked, users will be removed from workspace"),
required=False,
)


class TransferMembershipForm(form.SchemaForm):
schema = ITransferMembershipForm
ignoreContext = True

label = u"Transfer membership"

@button.buttonAndHandler(u"Ok")
def handleApply(self, action):
data, errors = self.extractData()
if errors:
self.status = self.formErrorsMessage
return

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_id = api.user.get(username=member).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."
6 changes: 6 additions & 0 deletions src/ploneintranet/workspace/profiles/default/actions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,11 @@
</property>
</object>

<!-- Add copy/move tab on our workspace -->
<object name="ws_transfer_membership" meta_type="CMF Action" i18n:domain="plone">
<property name="title" i18n:translate="ws_transfer_membership_tab">Transfer Members</property>
<property name="url_expr">string:${context/absolute_url}/transfer</property>
<property name="available_expr">python:context.portal_type == "ploneintranet.workspace.workspacefolder"</property>
</object>
</object>
</object>
115 changes: 115 additions & 0 deletions src/ploneintranet/workspace/tests/test_forms.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from collective.workspace.interfaces import IWorkspace
from zope.interface import Interface
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.component import provideAdapter
from plone import api
from ploneintranet.workspace.tests.base import BaseTestCase
from ploneintranet.workspace.browser.forms import PolicyForm
from ploneintranet.workspace.browser.forms import TransferMembershipForm
from z3c.form.interfaces import IFormLayer
from zope.publisher.browser import TestRequest
from zope.interface import alsoProvides
Expand Down Expand Up @@ -97,3 +99,116 @@ def test_policy_form(self):

self.assertEqual(workspace.external_visibility,
api.content.get_state(obj=workspace))


class TestTransferForm(BaseTestCase):

# Form setup gubbins stolen from:
# http://plone-testing-documentation.readthedocs.org/en/latest/z3c.form.html # noqa
def make_request(self, ws_uid, move=False):
""" Creates a request
:param str ws_uid: workspace uid to transfer users to
:param bool move: if True, delete from current workspace
:return: submitted request.
"""

# WARNING: browser creates a proper checkbox field in the form,
# while test makes it as a radio button. For selected
# checkbox value should be: [u"selected"], and selected radio
# has a value of ["true"]

form = {
'form.widgets.workspace': [ws_uid],
'form.widgets.move': [str(move).lower()],
'form.buttons.ok': 'Ok',
}

request = TestRequest()
request.form.update(form)
alsoProvides(request, IFormLayer)
alsoProvides(request, IAttributeAnnotatable)
return request

def create_user(self, name="testuser", password="secret"):
""" Creates a request
:param str name: username, default="testuser"
:param str password: password, default="secret"
:return: user object
"""

user = api.user.create(
email=name + "@user.com",
username=name,
password=password,
)
return user

def test_transfer_form(self):
""" Check that the transfer form can copy/move users
to another workspace """
self.login_as_portal_owner()

provideAdapter(adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=TransferMembershipForm,
name="transfer")

ws = api.content.create(
self.portal,
"ploneintranet.workspace.workspacefolder",
"alejandro-workspace",
title="Alejandro workspace")

names = "Dima Nikita Alex Vlad Sergey".split()
for name in names:
IWorkspace(ws).add_to_team(
user=self.create_user(name=name).getId())

# subtracting admin from members list
self.assertEqual(len(names), len(list(IWorkspace(ws).members))-1)

other_ws = api.content.create(
self.portal,
"ploneintranet.workspace.workspacefolder",
"isabella-workspace",
"Isabella Workspace",)

# copy users
request = self.make_request(api.content.get_uuid(other_ws))
transfer_form = api.content.get_view('transfer',
context=ws,
request=request)
transfer_form.update()
data, errors = transfer_form.extractData()
self.assertEqual(len(errors), 0)

self.assertEqual(len(names), len(list(IWorkspace(ws).members))-1)
self.assertEqual(len(names), len(list(IWorkspace(other_ws).members))-1)

# now move users
# WARNING: browser creates a proper checkbox field in the form,
# while test makes it as a radio button. For selected
# checkbox value should be: [u"selected"], and selected radio
# has a value of ["true"]
request = self.make_request(api.content.get_uuid(other_ws), True)
form = api.content.get_view('transfer',
context=ws,
request=request)
form.update()
data, errors = form.extractData()
self.assertEqual(len(errors), 0)

self.assertEqual(len(names), len(list(IWorkspace(other_ws).members))-1)
self.assertEqual(0, len(list(IWorkspace(ws).members)))

# now move users back
request = self.make_request(api.content.get_uuid(ws), True)
form = api.content.get_view('transfer',
context=other_ws,
request=request)
form.update()
data, errors = form.extractData()
self.assertEqual(len(errors), 0)

self.assertEqual(0, len(list(IWorkspace(other_ws).members)))
self.assertEqual(len(names), len(list(IWorkspace(ws).members))-1)

0 comments on commit 6299f99

Please sign in to comment.