Enable Workspaces in your site
Workspaces as seen on plone.org are useful if you want to have a controlled content creation scheme.
Its very often that you want to specify policies of where content will be physically stored.
A good example of this is how plone.org uses them. All News Items are stored in
plone.org/newsitems and Events are stored in plone.org/events - this organization
also lends itself to storing content in separate databases, especially in 2.7 where
DBTab comes stock with the application.
An added bonus of how this system works is in the usage of CMFFormController to
repurpose the newsitem and event edit actions. Watch ;-)
Requirements
- !PloneWorkspaces found at sf.net/projects/collective (USE CVS)
- !CMFWorkspaces found at cvs.zope.org/CMF (USE CVS)
- !CMFPlone 2.0RC2 or later (including CMFFormController 1.0b4+)
- CMF 1.4.2 +
- Zope 2.6.2 +
In $INSTANCE_HOME/Extensions create a file called workspaces.py:
from Products.CMFCore.utils import getToolByName
from Products.CMFWorkspaces.References import PortalRelativeReference
def getReferenceFor(self, obj):
return PortalRelativeReference(obj)
def addMemberWorkspace(self, user=None):
mt=getToolByName(self, 'portal_membership')
ut=getToolByName(self, 'portal_url')
pt = getToolByName( self, 'portal_types' )
RESPONSE=self.REQUEST.get('RESPONSE', None)
portal=ut.getPortalObject()
if user is None:
user=mt.getAuthenticatedMember()
userid=user.getUserName()
if 'workspaces' not in portal.objectIds():
apply( pt.constructContent ,
('CMF BTree Folder', portal, 'workspaces', RESPONSE) ,
{} )
workspaces = portal.workspaces
if userid not in workspaces.objectIds():
apply( pt.constructContent ,
('Workspace', workspaces, userid, RESPONSE) ,
{} )
workspace = getattr(workspaces, userid)
acl_users=portal.acl_users
zuser=acl_users.getUserById(userid)
if zuser is None:
acl_users=portal.aq_parent.acl_users
zuser=acl_users.getUserById(userid)
workspace.changeOwnership(zuser.__of__(acl_users))
return workspace
In portal_skins/custom (or whatever your custom folder is called) and create these External Methods
- id: addMemberWorkspace
- module: workspaces
- function: addMemberWorkspace
- id: getReferenceFor
- module: workspaces
- function: getReferenceFor
Now in portal_skins/custom, create a (Script) Python called, goto_workspace
- id: goto_workspace
- parameters:
body:
member=context.portal_membership.getAuthenticatedMember()
context.addMemberWorkspace(member)
workspace=context.workspaces[member.getId()]
return context.REQUEST.RESPONSE.redirect(workspace.absolute_url())
Now in portal_skins/custom, create a Controller Python Script called, createObjectInWorkspace
- id: createObjectInWorkspace
- paramters: id=None, type_name=None, script_id=None
body:
type_name=context.REQUEST['type']
context.createObject(id=id, type_name=type_name, script_id=script_id)
return state
Provide at least an action in case of succesful Controller by going into Action
- status: success
- context: Any
- action: redirect_to_action
- Argument: string:edit
Create a Controller Python Script that will be called after News Item and Event are added/edited.
- id: associateContentToWorkspace
- parameters:
body:
member=context.portal_membership.getAuthenticatedMember()
space=context.portal_url.getPortalObject().workspaces[member.getUserName()]
space.addReference(state.getContext())
state.setNextAction('redirect_to_action:string:view')
# Make sure to return the ControllerState object
return state
In the root of your plone create a CMF BTreeFolder called workspaces, this is where members's workspaces will be held.
Also in the root of your plone (in the Zope Mgmt Interface) create a CMFWorkspaces Tool (Portal Organization Tool)
Now goto portal_membership and lets add a action:
- name: My Workspace
- id: myworkspace
- action: python: portal.absolute_url()+
/goto_workspace - condition: member
- permission: View
- category: user
Goto the portal_organization tool that has been created, click on the placement tab and add:
- CMF Type: News Item
- path: /newsitems
- factory: createObjectInWorkspace
- CMF Type: Events
- path: /events
- factory: createObjectInWorkspace
Now finally we are going to make it so that when newsitem_edit or event_edit is called after the form
is validated it will add the item to the workspace. Goto portal_form_controller and click on Actions
- template/script: event_edit
- status: success
- context: Any
- button:
- action: traverse_to
- arguement: string:associateContentToWorkspace
- template/script: newsitem_edit
- status: success
- context: Any
- button:
- action: traverse_to
- arguement: string:associateContentToWorkspace
Lastly in Plone 2.0 we are using a really insane hack called portal_factory. But is quite nice ;-) This comes turned off
for plone by default. Its the portal_factory tool from the ZMI. You can Factory Types tab and select what content types
you would like to use portal_factory when you add one. NOTE: When add a piece of content it will not save the object
automatically to the ZODB. It will create a temporary object than when the user clicks save and the form validates it
will create the object, edit the object and save. That is done in newsitem_edit, we have overridden this action after
newsitem_edit we tell it to traverse_to associateContentToWorkspace script which will add it to the users workspace.
Please help by making comments to this document to help others. If a client pays me to wrap this up into a nice little package. I would love to. Although I would use the ReferenceEngine in Archetypes instead of the OrganizationTool. Thanks to Shane Hathaway, Tres Seaver and Zope Corp. for CMF and CMFWorkspaces.
is there an easier way?
I tried Workspacegear 0.3.1 but never got it to run, and there is no documentation (in english atleast).