Building Custom Content Types with ArgoUML and ArchGenXML and Permitting Anonymous Content Submission
Note: Return to tutorial view.
Overview and Prerequisits
Preamble
While I've found good documentation on may different aspects of Plone customization and development, I found it difficult to bring the information from those sources together into something I could use to accomplish a customization goal.This documentation is based on my first pass at custom content type and my first major Plone customization. As such, I'm sure it's not done in an optimal manner, and probably won't work for you at all. In fact, I have no idea what I'm doing whatsoever. So, consult this information at your own risk. Also, if you know a better approach to the things I'm doing, please post a comment so that I can learn from that as well.
Overview
Up until this point, my organization had simply used Plone for storing uploaded files on the intranet. PDFs, Office documents, etc and the greatest selling points for us on this tool was it's ease of use and fantastic search capibilities. Users had broad access to upload and modify files, and workflow was largely ignored.We needed a business suggestion submittal system that would take anonymous submissions from intranet users and allow those submissions to go through an approval/rejection process that was visible to the end users.
We wanted to be able to add custom content via a form, and have that data change permissions as it traveled through a proper workflow. We also wanted to to allow anonymous intranet users to be able to make these submissions, and have visibility to the documents as they progressed through the workflow.
I started by building in archtype by hand, which worked. But, as I was/am new to Plone/Zope, it was a little hard to get started, and I didn't feel like I was making good progress. Then in my research, I found a better way. I could design my data form and my desired workflow in UML and have that converted to the base Plone product. Once that was customized and the correct permissions defined I could finish my project in a very short period of time.
Prerequisites
Most of the tutorials I found were not targeted at the complete novice, so I'll try to explain in as much detail as possible.That being said, setup and installation is beyond the scope of this document. You will need the following software, though:
- ArgoUML
- Be sure to install the ArchGenXML profile listed at the bottom of this ArgoUML+ArchGenXML tutorial.
- ArchGenXML
- Plone 2.1+
- Python
My development environment is Plone 2.5 running on WindowXP, though this process should work regardless of your environment. The code I developed in this env was deployed to a Plone 2.1 instance running on Redhat Enterprise Linux 3.
Creating a Class and Workflow with ArgoUML and ArchGenXML
ArgoUML
ArgoUML is a diagramming tool similiar to Visio, but better cause it's Open Source, and cross platform. It's a Java thick client application, so you'll need a Java Runtime Environment before you can run it. Again, I won't cover installation, but once you get it all installed and the ArchGenXML profile configured, fire it up.Creating the Class
The Class is the business object that will be holding all the information that we'll be collecting from the users. We define what kind of data we want it to hold, and put in a few configuration parameters, and ArchGenXML and the archetypes framework will create the forms for us. Hurray for Archetypes!- First we're gonna make a package to store all of our classes in. In the example, it doesn't make much of a difference, but it's probably a good habit to have, so click on the New Package icon on the top of the main diagram area and then click in the diagram area.
- Stretch the corner out to it takes up most of the screen. On the bottom of the screen, in the properties tab, give your package a name like "ProcessImprovement".
- Now click on the New Class icon on the top, next to the New Package icon, and click inside of your package. You've just created a class. Give it a name like "ImprovementSuggestion".
- Now we'll start defining some datatype. The ArchGenXML supports a whole series of Archetype predefined datatypes and they're associated requestor widgets (quick reference). We're going to keep this real simple and use just three fields:
- Name (String): To hold the user's name, since users need not be logged in in our senerio, this field will allow them to manually enter their name.
- Suggestion (Text): This will be a basic text area for them to enter their suggestion. If you wanted to get fancy you could Rich type and allow HTML and the fancy Kupu editor input.
- ImprovementArea (Selection): This will be a selection list of possible choices. It will allow the users to select the area the improvement will impact from a list.

- Next we need to put some additional information into the class diagram so that ArchGenXML know how to display the fields, and addition option that we have available to us. We do that by giving each field tagged values. Click on the Name field one time to select it, and then click on the "Tagged Values" tab in the bottom pane. This is where we're going to put our widget and field configuration. Enter the following Tagged Values in the Name data element:
- widget:label = Your Name
This is what the form field will be labeled. If it is not specified, the label will default to the name of that field. - widget:description = Enter your name, or 'Anonymous'
This is the description of the form field displayed on the page. - required = True
Whether or not the field is required. - searchable = python: True
By prepending the entry with "python" ArchGenXML will not process the text that follows, it will just pass it directly. This entry will ensure that the field can be searched on.
- widget:label = Your Name
- Click on the Suggestion field and enter the following Tagged Values:
- widget:label = Your Suggestion
This is what the form field will be labeled. If it is not specified, the label will default to the name of that field. - widget:description = Enter your improvement suggestion with as much detail as possible.
This is the description of the form field displayed on the page. - required = True
Whether or not the field is required. - searchable = python: True
By prepending the entry with "python" ArchGenXML will not process the text that follows, it will just pass it directly. This entry will ensure that the field can be searched on.
- widget:label = Your Suggestion
- Click on the ImprovementArea field and enter the following Tagged Values:
- widget:label = Improvement Area
This is what the form field will be labeled. If it is not specified, the label will default to the name of that field. - widget:description = Enter the area that your suggestion will affect.
This is the description of the form field displayed on the page. - required = True
Whether or not the field is required. - searchable = python: True
By prepending the entry with "python" ArchGenXML will not process the text that follows, it will just pass it directly. This entry will ensure that the field can be searched on. - vocabulary = python:["Sales", "Help Desk", "Factory Floow", "Other (please specify above)"]
vocabulary take in a python list, and will make a select list out of it. It will automatically determine whether it should be a drop down list or a series of radio buttons, depending on how many entries you have.
- widget:label = Improvement Area
- One last thing before we generate our initial Zope Product. In the navigation tree in the left hand pane, click on "untitledModel", and give it a name in the Properties pane on the bottom. Name it "ProcessImprovement".
- Now, save this file as "ProcessImprovement.zargo". Pull up a command prompt and navigate to that directory. Make sure that you've added the ArchGenXML directory to your env path, and type the following:
C:\Sandbox\Plone\Tutorial>ArchGenXML.py ProcessImprovement.zargo
ArchGenXML 1.4.0-beta2
(c) 2003-2005 BlueDynamics KEG, under GNU General Public License 2.0 or later
INFO Parsing...
WARNING Empty package: '.:0000000000001DE2'.
WARNING Empty package: '.:0000000000001DE2'.
INFO Directory in which we're generating the files: ''.
INFO Generating...
WARNING Can't build i18n message catalog. Module 'i18ndude' not found.
WARNING Can't strip html from doc-strings. Module 'stripogram' not found.
INFO Starting new Product: 'ProcessImprovement'.
INFO Generating package '.:0000000000001DE2'.
INFO Generating package 'ProcessImprovement'.
INFO Generating class 'ImprovementSuggestion'.This will have generated a complete Plone Product called "ProcessImprovement".
- Copy the entire "ProcessImprovement" directory tree into your Plone Products directory. Restart your Plone service, log in as a user with administrative priviliges, go to the site preferences and click on "Add/Remove Products".

Check the checkbox next to the new Product and click "install". Congratulation! You've just built your first custom Plone product! - You should now be able to navigate to any folder in the Plone website, and add an "improvementsuggestion" content type. It should look something like this:

- Feel free to go back and add additional content types. There some really cool ones like "File". Also toy with the available options for each. Be sure to poke around the generated code. We'll be digging into that later on, so get familiar with it now.
Creating the Workflow
The workflow is path through which the Class we just defined travels. In our case there will be two paths, one of approval and one of rejection. First we'll draw out the states, then we'll define how one gets from one to the next, and finally will fill in some detail on the process. We'll be working with a StateChart diagram. If you're unfamiliar with what one of those is, there is some good basics on StateChart Diagrams here.- Go back to AgroUML and the class that we just completed. Click on the ImprovementSuggestion class, and then select Create->New Statechart Diagram from the top menu. Click on "(anon StateMachine)" in the left nav tree and give the workflow a name in the Properties tab on the bottom. Name it "ImprovementSuggestionWorkflow".
- In the main chart area, add a new "Initial". It looks like a solid black dot. Drop it on the left hand side of the workspace, and give it a name (in the Properties tab) of "Creating".
- Next add a new Simple State (looks like a rounded box with a horizontal line in it) a to the right of the Initial. Name this one "Submitted".
- Above and to the right of Submitted, add another Simple State called "Approved".
- To the right of "Approved", and another Final State (circle with black dot inside of it) called "Complete".
- Below "Approved", add a Final State called "Rejected".
- Now click on the Inital and drag a connecting line from it to "Submitted". Connect Submitted to both "Approved" and "Rejected". And finally connect "Approved" to "Complete". The completed diagram should look somthing like this:

Business types LOVE this kinda stuff. So take a screenshot of this workflow, throw some labels on it and send it off to them right way. CC your boss, and then followup and ask for a raise. You deserve it! - Now we're going to go back and name out state transitions (the connecting lines). The transistion going into Submitted should be names "Submit", the trans going into Approved should be called "Approve", the trans going into Rejected should be called "Reject" and the trans going into Completed should be called "Complete". Click on each transition state and set it's name in the Properties tab on the bottom of the screen.
- We need to define what kind of users can trigger different state transitions. We have anonymous users to be able to Create (an initial state) and Submit (a state transition) requests, but we don not want them approving. We want Managers and Reviewer to be able to approve/reject/complete the Suggestions. But, we want anonymous users to be able to view the requests all the way through the process.
To accomplish this, we'll start by setting the permissions on all the states. Click on the Submitted state, and go to the Tagged Values tab. We're going to add a tagged value for each permission on that state and the groups that should have that access. Add the following tags:- view=Anonymous
- list=Anonymous
- access=Anonymous
- modify=Manager, Reviewer
- Go through and give the same Tag Values to the Approved, Complete and Rejected states.
- Next we'll add "guards" to the state transitions that will define who can, and cannot trigger those state changes. The first state transistion (Submit) should be available to everyone, so we won't put a guard there, but we will on the rest. Click on the "Approve" state transition, and find the "Guard" form field in the Properties tab. Right click in that and select "New" (your only option). Give the new Guard a name of "Approve", and in the expression field (on the right) enter "guard_roles:Reviewer;Manager". This will limit that transistion's availablity to those two groups.
- Do the same for the Reject and Complete state transitions. Permissions are now done.
- TODO: Define worklist, and provide clarification about how it functions and what it does.
- Your workflow is now complete! Run the same cli as in step #9 of "Creating the Class" section above.
C:\Sandbox\Plone\Tutorial>ArchGenXML.py ProcessImprovement.zargo
ArchGenXML 1.4.0-beta2
(c) 2003-2005 BlueDynamics KEG, under GNU General Public License 2.0 or later
INFO Parsing...
WARNING Empty package: '.:00000000000021E3'.
WARNING Empty package: '.:00000000000021E3'.
INFO Directory in which we're generating the files: ''.
INFO Generating...
WARNING Can't build i18n message catalog. Module 'i18ndude' not found.
WARNING Can't strip html from doc-strings. Module 'stripogram' not found.
INFO Starting new Product: 'ProcessImprovement'.
INFO Generating package '.:00000000000021E3'.
INFO Generating package 'ProcessImprovement'.
INFO Generating class 'ImprovementSuggestion'.
INFO Generating workflow 'ImprovementSuggestionWorkflow'.
INFO Generating workflow script(s). - Copy your directory over to your Plone products directory again, restart Plone and go back to the Add/Remove Products section. The product is still installed, but now will need to be upgraded. Click the link next to your product to upgrade it.
Anonymous Content Submission
The Requirement
So far we've created a business object and defined the workflow through which it will operate. We could be done now, if all of our users had member accounts. But for the purposes our business, we want anonymous users to be able to submit these suggestions. This is good because:- Since this is a suggestion box, we want staff to be able to submit a suggestion under the guise of anonymous submission. In reality, I could track them down by IP address and such, but they don't know that.
- I don't want to have to maintain user accounts for 500 people. Yes, I know I could integrate into our MS AD, or some such nonsense, but this is easier.
Anonymous Content Addition
We don't want users to be able to add content everywhere, though. Just in one folder, so we'll start by creating that.- Go into your Plone instance and create a folder off of the Root called "Suggestions". And in that folder, create another folder named "Archive". We're going to be creating the actual improvementsuggestions in the "Archive" folder, and putting smartfolders in the "Suggestions" folder, as you'll see later on.
- Now, go into the ZMI. Yes, I know it's scary. Yes, you've been told to stay away and set permissions in a different manner, but this is they way we're gonna do it.
- Browse to the /Suggestions/Archive folder and click on the properties tab. You will see a huge grid of permissions. Do not be afraid. Scroll down until you see "add portal content". Uncheck the "Aquire" box on the left, and check the "Anonymous" and "Authenticated" boxes on the right.
- Scroll down until you see "modify portal content". Make sure "Aquire" is unchecked and check "Anonymous" and "Authenticated".
- Scroll down to the very bottom of the page and click "Save Changes".
- Now close your web browser completely (or pull up a different one. I user Firefox for dev, so I just pull of IE for this testing so I can keep my ZMI on screen), and go to your website. Do not log in. Browse to the /Suggestions/Archive folder. You should be able to add a "improvementsuggestion" type object.
- TODO: Define custom permission for the ImprovementSuggestion type so that containing folder can be controlled the objects inside of it. Right now, with this configuration, the folder is editable by anonymous, and this is undesirable.
- Great! Anonymous users can now add content, but there's a problem.
Preventing Anonymous Users from Editing
Now that anyone can add content, it's important to prevent those same anyones from being about to delete or modify that submitted content. The way we will be handling this is to add a script that is executed automatically when the new content is saved that progresses it in it's workflow process. We will move from the "Creating" state to the "Submitted" state. If you remember (or click back on your browser), the Submitted state only allows modification of content by Managers and Reviewers, and not anonymous users. We will be using a technique that I took from the PloneJobBoard project.We're gonna getting into the nitty gritty here. We'll be editing files with a text editor. One thing to know is that the changes that we're making will be overwritten if you regenerate the project with ArchGenXML. So make sure you have your project checked into your CVS/Subversion system so you can diff the changes back in. Or, just don't regenerate after this point...
- Go into your /Products/ProcessImprovement/skins/ProcessImprovement folder and create the following two files. They comprise a script that will be executed and automatically propel the workflow.
/Products/ProcessImprovement/skins/ProcessImprovement/ improvementsuggestion_post.cpy## Script (Python) "improvementsuggestion_post"
##title=Post ImprovementSuggestion after validation
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind state=state
##bind subpath=traverse_subpath
##parameters=
##
from Products.CMFCore.utils import getToolByName
workflow = getToolByName(context, 'portal_workflow')
workflow.doActionFor(context, 'Submit')
return state.set(status = 'success',
portal_status_messsage = 'Thank you.')/Products/ProcessImprovement/skins/ProcessImprovement/ improvementsuggestion_post.cpy.metadata
[default]
title = Submit a suggestion
[validators]
validators =
[actions]
action.success = redirect_to:string:../
action.failure = traverse_to:string:content_edit - Open up the /Products/ProcessImprovement/Extensions/Install.py file and do a search for the following:
print >>out,'no workflow install'
immediatly following that line, add the following
controller = getToolByName(self, 'portal_form_controller')
addFormControllerAction(self, out,
controller,
template = 'validate_integrity',
status = 'success',
contentType = 'ImprovementSuggestion',
button = '',
actionType = 'traverse_to',
action = 'string:improvementsuggestion_post')and add this to the bottom of the file
def addFormControllerAction(self, out, controller, template, status,
contentType, button, actionType, action):
"""Add the given action to the portalFormController"""
controller.addFormAction(template, status, contentType,
button, actionType, action)
print >> out, "Added action %s to %s" % (action, template) - Now try anonymously creating a ProcessImprovement document. You should be able to view it after creation, but not edit it and it's state should be "Submitted" instead of the default of "Creating". Log in as a manager or reviewer and you should be able to progress it down it's workflow.