Warning

This document hasn't been checked for compatibility with current versions of Plone. Use at your own risk.

Using permissions and workflow in your custom products

by Martin Aspeli last modified Apr 24, 2010 04:42 PM
When you are developing a Plone site, it is usually best to develop your customisations or new content types on the filesystem, as a new Zope product. Setting up workflows programatically using the portal_workflow tool is a bit of a pain, but luckily there are tools to make your life much easier. You also need to ensure you use the correct permission declarations on your objects.

Explaining how to develop products and secure them properly is beyond the scope of this tutorial. Suffice it to say that to create re-usable Zope/Plone components, and for the sake of your own sanity, you should be developing your customisations and add-ons on the filesystem, as Zope products. Raphal Ritz' excellent MySite tutorial will give you a good and in-depth introduction to the topic.

Protecting your code

When creating classes which are intended to be accessed through the web (typically Archetypes content types or portal tools, though this applies to any Zope class derived from ExtensionClass) you must add security assertions on your methods. Much more information about this can be found in the Zope Developer Guide.

The following code example shows a general paradigm that is frequently followed in Archetypes products using the CMF core permissions. Please refer to the developer guide's chapter 6 for more details:

  from AccessControl import ClassSecurityInfo
  from Products.CMFCore import CMFCorePermissions
  # ... (additional imports and initialisation)

  class MyType(BaseContent):

    # ... (initialisation of schema and factory type info)

    # create a class security object to handle our security policy
    security = ClassSecurityInfo()

    # set a method to be publically accessible - all TTW code can
    # call this directly
    security.declarePublic('publicMethod')
    def publicMethod(self):
      # ... (docstring and method body)

    # set a method to be private - no TTW code can call this directly
    security.declarePrivate('privateMethod')
    def privateMethod(self):
      # ... (docstring and method body)

    # set a method to be protected by a given permission.
    # Only users with this permission in the context can call
    security.declareProtecte(CMFCorePermissions.View, 'protectedMethod')
    def protectedMethod(self):
      # ... (docstring and method body)

  # ... (type initialisation)

This rather amputated example shows how a class creates a ClassSecurityInfo object and uses it to declare its methods public (accessible to all through-the-web code), private (not accessible through the web) or protected by some permission - in this case the CMF core permission View. As with all matters of security, you should always protect your methods by the most limiting permission possible to ensure security is not breached.

Creating new workflows

Workflows can be created through the portal_workflow user interface. If you wish to ship such a workflow with your product, you must dump it to a python file and register it during Install.py. There is a dedicated product for this called DCWorkflowDump. When installed (just put it in your Products folder, no Plone installation necessary), it will give you a Dump tab when viewing a workflow in the ZMI to create a file containing the setup code for your workflow.

Typically, this workflow definition is dumped into your product's Extensions/ folder and called during Install.py to set up your workflow. If you subsequently wish to make changes to your workflow, you may wish to modify this dumped code directly rather than use the GUI and re-dump, as it is likely to be quicker. The dumped code should be fairly easy to understand once you know a bit about workflows.

An alternative way of creating workflow definitions is ArchGenXML. Using this tool, you can create UML state diagrams to represent your workflows. See the ArchGenXML documentation for details.

Finally, once your workflow has been created, you must register it with the workflow tool and associate any types you want with it (ArchGenXML does all of this automatically for you). The following code snippet is adapted from the PloneHelpCenter - the fine software that runs this documentation section - also found in the Collective. You may want to look at that product in more detail (a CVS checkout will be preferable) to see how workflows are used "in real life". In Extensions/Install.py, you may wish to put:

    # ...  (header and imports)

    def install(self):

        # ... (additional installation and setup)

        # Get our workflow and install it
        from Products.MyProduct.Extensions import MyWorkflow

        # The PloneHelpCenter does this, because it modifies the
        # dumped file to put the installation-initiating code inside
        # a method called install(). By default, it is called
        # automatically as soon as the workflow module is imported.

        # HCWorkflow.install()

        # Register the workflow with the tool 
        wf_tool = getToolByName(self, 'portal_workflow')

        # The id of the workflow if my_workflow, and the title is
        # My custom workflow. Due to a dumb API, these names have
        # to be entered verbatim in the argument to the method
        # below, with spaces and parentheses as shown.

        if not 'my_workflow' in wf_tool.objectIds():
            wf_tool.manage_addWorkflow('my_workflow (My custom workflow)',
                                       'my_workflow')

        # Do this after installing all workflows   
        wf_tool.updateRoleMappings()

        # Now tell our custom type MyType to use this workflow
        wf_tool.setChainForPortalTypes(pt_names=['MyType'], 
                                       chain='my_workflow')

        # ... (additional installation and setup)

That should be it - your custom workflow should be available for use after you install (or re-instal) your product. You are encouraged to take a look at the PloneHelpCenter code for a more comprehensive example.


Contribute

Something wrong or out of date? Anybody can edit or create a new article in the knowledge base. Simply create an account on this site, log in, and click the Edit button to contribute.