Commit 6f3a61b0 authored by Charlie Clark's avatar Charlie Clark

Moved to `docs` folder.

parent 4fabc6d6
Overview
DCWorkflows provide workflow objects that are fully customizable via
the Zope Management Interface. You can specify the states, and the
permissions they set on content that is in that state, the transitions
between those states, and other things like variables for things that
aren't well represented by states, work lists for reviewers, and
scripts to embody complex guards and to extend pre and post transition
behaviour.
The process for creating a workflow runs something
like this:
- Draw a state diagram with the nodes (bubbles) as states and the
arcs (arrows) as transitions. Remember to consider all the states
your content can be in, and for each state, consider who should
have permission to access and change the content. Consider what
actions the users will perform to make the transitions between states,
and not only who will be allowed to perform them, but who will be
*required* to perform them.
It's often a good idea to start on paper, then transfer
the diagram to a digital copy using a diagram/flowchart tool, such as
'dia', so that you have an image to go with later documentation. This
process tends to make it easier to spot corner cases before you
actually create the workflow object.
- Start by creating an example DCworkflow, rather than a new one, as it's
faster to delete all the states and transitions than it is to create all the
standard variables that tend to be used by the CMF. [**Note:**
Perhaps we should have a bare dcworkflow, a workflow with standard
variables, and the couple of standard examples.]
- In the permissions tab, select all the permissions that you want the
workflow to govern. These will be dependent on the types of content
you'll be using with the workflow; 'Access contents information',
'Modify portal content', and 'View' are the standard permissions for
the default portal content types.
- Define any extra variables that you need for information that isn't
well represented by states. [**Note:** generic examples? I can think of
a few that could appear in some use cases, but they're all
idiosyncratic of particular publishing needs]
- Set up the states for your workflow, one for each node in your state
diagram. Try to stick to the standard names for a publication workflow, as
some badly behaved products have states like 'published' hardcoded into
their searches (ie CalendarTool, last I looked) [**Note**: Maybe I
should just file some bug reports rather than casting aspersions :-)].
Set up the permissions on the states now, as well, though see the
"State Tab" section for advice.
- Set up any scripts that you will be using in your transitions, such
as pre and post transition scripts and to handle complex guard
conditions. Just set up skeletons for now, if you haven't though
through all the details.
- Create your transitions from all the arcs on your state diagram. You
should be able to pick the right destination state as all your states
are already defined, and set up the right scripts to run, as you've
defined those as well. It's worth noting that the guard behaviour is
such that if any guard matches, the transition can occur. You can
specify more than one permission, role or expression by separating
them with a semicolon.
- Go back to the states tab and, for each state, set the possible
transitions from the list of all available transitions in each state.
- Finally, in the work lists tab, create any work lists for any states
that need them. Work lists are actions that indicate how many objects
of a given state are present, and usually link to some search page
that lists the actual object instances. You typically use them to list
all the pending content waiting for review. Work lists have several
unusual behaviours, however, so check the specific notes in the
"Worklists" section.
By working in this order, you will tend to step through the
creation process one tab at a time, rather than switching back and
forth between them, which tends to be slower and somewhat confusing.
Expressions
Expressions in DCWorkflow are TALES expressions. See
"TALES Overview":/Control_Panel/Products/PageTemplates/Help/tales.stx
for general TALES information. They are used as access guards and for
the setting variable values.
[**Note:** I haven't figured out what all these contexts actually are
and what you can use them for. Explanations are is welcome!]
Some of the contexts have slightly different meanings from what is provided
for expressions in page templates:
'here' -- The content object (rather than the workflow object)
'container' -- The content object's container
Several other contexts are also
provided:
'state_change' -- A special object containing information about the
state change (see below)
'transition' -- The transition object being executed
'status' -- The former status
'workflow' -- The workflow definition object
'scripts' -- The scripts in the workflow definition object
'state_change' objects provide the following attributes, some of which
are duplicates of the above information:
- 'status' is a mapping containing the workflow status. This
includes all the variables defined in the variable tab with "store
in state" checked.
- 'object' is the object being modified by workflow.
(Same as the 'here' variable above.)
- 'workflow' is the workflow definition object. (Same as the
'workflow' variable above.)
- 'transition' is the transition object being executed. (Same
as the 'transition' variable above.)
- 'old_state' is the former state object. The name of the former state,
for example "published", is available as 'old_state.getId()'. (Note
that DCWorkflow defines 'state' and 'status' as different entities;
the name of the current 'state' is stored in the 'status'. The word
clash is unfortunate; patches welcome.)
- 'new_state' is the destination state object. Use 'new_state.getId()'
to access the new state name.
- 'kwargs' is the keyword arguments passed to the doActionFor() method.
- 'getHistory()', a method that returns a copy of the object's workflow
history.
- 'getPortal()', which returns the root of the portal.
- 'ObjectDeleted' and 'ObjectMoved', exceptions that can be raised by
scripts to indicate to the workflow that an object has been moved or
deleted.
- 'getDateTime' is a method that returns the DateTime of the transition.
Guards
Guard settings control access to the transitions, variables or work
lists. Guards can be applied based on permissions, roles, groups or
a TALES expression. These elements are applied sequentially if they
contain values. If one of the conditions in each of the specified
permissions, roles or groups is met the guard element will be
satisfied. For the guard to allow access, all specified element that
contain values must be satisfied.
If no permissions, roles or expressions are specified, access is
automatically granted.
You can supply several options in each field by separating them with
a semicolon.
The context in which the guards evaluate permissions and roles is
obviously important. In the case of transitions and work lists, it
depends on the category. If it's 'worklist', then the context is
that of the content object, and local roles will behave just as
you'd expect. If the category is 'global', then the context will be
the site root, so the local roles between the site root and the
content won't be considered.
[**Note:** What about variables?]
Action Boxes
Action box settings are required for work lists and any transition that
is intended to be a user initiated action. They define how the action
will appear in the action box, what section it will appear in and
what it will link to.
Names and URLs for the actions box can be formatted using standard Python
string formatting. An example::
%(content_url)s/content_submit_form
The string '%(content_url)s' will be replaced by the value of content_url.
The following names are available:
- portal_url
- folder_url
- content_url
- count (Available in work lists only. Represents the number of items in
the work list.)
The following names are also available, in case there is any use for them.
They are not strings.
- portal
- folder
- content
- isAnonymous
Note that this formatting is done using standard Python string formatting
rather than TALES. It might be more appropriate to use TALES instead.
As always, patches welcome.
States Tab
From the states tab it's possible to add new states, and rename and
delete existing states. It is also possible to set a particular state
to be the initial state that new content is set to when created.
The list of existing states also displays each state's title and all
the possible transitions from that state (and their titles). You can go
straight to the details of each state and transition from here.
Within a state's properties tab you can set the title, description,
and the transitions that are possible from this state from a list of
all the available transitions created in the workflow's
transitions tab.
In the state's permissions tab, you can set up the roles to
permissions mappings that will apply to roles when content
managed by this workflow is in this state. It uses the usual cookie
cutter approach as do all other permissions tabs, except that the
only permissions listed are those that have been selected to be
managed by the workflow from the workflow's permissions tab.
A good strategy for managing permissions on each state is to rely on
acquisition for the "published" states, and to drop acquisition and
use explicit permissions on states that are private or interim
publishing states. This way, you can modify the access policy to
"published" content at the site root or for specific folders without
having to modify each workflow's set of "published" states.
[**Note**: The available roles in the permissions tab will be
whatever is acquired from the site root, so I guess creating
roles under sub-folders ought to be discouraged if people want
to use them in workflows]
Reviewer roles should either have view permissions on every
state or you should change the appropriate skins to take them
somewhere sensible after a transition or they'll end up with an ugly
access denied page after sending content back to private state.
In the state's variables tab, you can add, change and delete variables
that you want to assign a value to when objects move into
this state. The available variables are set in the workflow's
variables tab, and the value is a TALES expression (see Expressions
for more details).
Transitions Tab
Transitions are the actions that move content from one state in the
workflow to another. From the transitions tab it's possible to add new
transitions, and rename and delete existing transitions.
The list of existing transitions also displays a summary of each
transition's title, description, destination state, trigger, guards,
and action box entry. You can click through each transition to access
their details.
Within a transition's properties tab you can set the title, and
a collection of properties the define the transtion's behaviour, as
follows:
Destination state -- selected from all the states defined in the
states tab. A transition can remain in state, which is useful for a
reviewer adding comments to the review history, but not taking any
action, updating some variable, or invoking scripts.
Trigger type - There are two types:
- User actions are the familiar user initiated transitions activated
by actions in the action box.
- Automatic transitions are executed any time other workflow
events occur; so if a user action results in the content moving
to a state that has automatic transitions, they will be executed.
(You should use mutually exclusive guards to prevent indeterminate
behavior.)
Scripts - Perform complicated behaviours either before or after the
transition takes place. Scripts of all kinds are defined in the
workflow's scripts tab. Scripts called from here must accept only
one argument; a 'status_change' object. See Expressions for more
details.
Guards and Action boxes -- See the "Guards" and "Action Boxes"
sections for specific details about those fields. Note that
automatic transitions don't need the action box fields to be filled out.
What the action should link to.
In the transition's variables tab, you can add, change and delete
variables that you want to assign a value to, when the transition is
executed. The available variables are set in the workflow's variables
tab, and the value is a TALES expression (see Expressions for more
details).
Variables Tab
Variables are used to handle the state of various workflow related
information that doesn't justify a state of it's own. The default
CMF workflows use variables to track status history comments, and
store the the last transition, who initiated it and when, for example.
From the variables tab it's possible to add new variables, and rename
and delete existing variables.
The list of existing variables also displays a summary of each
variable's description, catalog availability, workflow status, default
value or expression and any access guards. You can click through to
each variable to configure it's details.
In each variable's property tab you can set the variable's
description and a collection of properties the define the variable's
behaviour, as follows:
Make available to catalog -- Just as it says, it makes this variable
available to the catalog for indexing, however it doesn't
automatically create an index for it - you have to create one by
hand that reflects the content of the variable. Once indexed, you can
query the catalog for content that has a particular value in is
variable, and update the variable by workflow actions.
Store in workflow status -- The workflow status is a mapping that
exists in the state_change object that is passed to scripts and
available to expressions.
Variable update mode -- Select whether the variable is updated on
every transition (in which case, you should set a default
expression), or whether it should only update if a transition or
state sets a value.
Default value -- Set the default value to some string.
Default expression -- This is a TALES expression (as described in
Expressions) and overrides the default value.
Guards -- See the "Guards" section.
State variable - stores the name of the variable the current state of
the content is stored in. CMF uses 'review_state' by default, and will
have already created a FieldIndex for it. The state variable is
effectively a variable with "Make available to catalog" set, a default
value of whatever the initial state is and a default expression that
sets to the new state on every transition.
Worklists Tab
Work lists are a way to make people aware of tasks they are required
to perform, usually reviewing content in the publishing context.
Work lists are implemented as a catalog query that puts an action in
the actions box when there are some tasks the member needs to perform.
From the work lists tab it's possible to add new work lists, and rename and
delete existing work lists. The list of existing work lists also
displays a short summary of each work list's description, the catalog query
it uses, and any guard conditions. You can access the details of each
work list by clicking on them.
In each work list's properties tab, you can set the description of
the work list, and it's various behaviour defining properties. The
"Catalog variable matches" field sets the state that is work list
matches. The "variable_name = " text to the left of the text box is
the name of the state variable defined at the bottom of the variables
tab. The values can be set to a number of possible matches separated
by semicolons. [**Note:** CVS feature. There's more in
doc/worklists.stx, but I'm not sure I understand the implications]
The action box fields are discussed in more detail in the Action Box
section. In this case, the url that the work list links to should
probably implement a search page with a catalog query similar to the
"Catalog variable matches", otherwise the difference between the
number of items waiting and the items reported in the search will be
confusing.
[**Note:** What we *really* need from the work list is a way to define
full catalog queries for the action, and a new action box variable
that urlquotes that query so it can be passed straight to the search
page. This way, the work list count and the number of items on the
search page will be the same as they are derived from the same
query string, defined in one place.
Reply from Shane: work lists already exercise the catalog too heavily,
and most people don't understand their purpose. Expanding their
capabilities further could impact performance. I think perhaps
the UI should instead display work lists on a user's home page rather
than the actions box, which would open up new possibilities.]
The guard fields are described in detail in the "Guards"
section. It's probably better to avoid using permission and role
guards, as they're not really necessary - a user will see a
work list action only if they can see content in that particular
state, so the state guards are usually sufficient. In addition, as
the work lists are in the 'global' actions category by default, and
global actions are evaluated in the context of the site root, local
roles like Owner or locally set Reviewer roles, and the permissions
they grant, will not apply. [*Note:* Does anyone know a good reason
why work lists appear in the global box rather than in the workflow
box? This particular problem should vanish if they are moved there.]
Whether a work list action appears in the action box, and the
number of items in the work list depends on several factors:
- The state that the work list is generated for
- The name of the state variable used to indicate the
current state of an object
- Whether the user can view content which is in that
state
This has some unexpected consequences:
- If you have several workflow that use the same state variable,
and similar state names, and each has a work list on, say, the
'pending' state, then both work lists will appear in the action box,
and the number of items in each will be the total of all the content
in a 'pending' state, regardless of which workflow manages that
content (except that if the work list action entries are exactly the
same text, the action tool will filter out the duplicate).
- If each workflow manages the permissions on content in the
'pending' state differently, by, say, using two different reviewer
roles, then users who have one role and not the other will
see a single work list entry with the right number of items, but
users with both roles will see the same as above.
So there are a few tricks to getting the work lists to do the kinds of
things we want.
If you have several similar workflows, such as a standard one, and a
couple of specialized ones for particular content, and you want to
have one reviewer role for the lot, then you should set up just one
work list in the standard workflow for the states that need them, and
leave the other workflow to rely on that work list.
If you have a workflow that uses a different reviewer role than
other workflows, and consequently, you want it to have it's own
separate work lists, you have two choices. One is to use state names
that are unique to each workflow, while the second is
to use state variable name that is unique each workflow. The
second option is obviously a lot easier, however, if you change the
name of the state variable when there exists content that is using
this workflow, they will immediately loose there workflow state
and default to the initial state. In addition, you'll need to add
a field index for the new state variable name in the portal_catalog
tool, by hand.
[Note: In the first instance, we could add an action box name field
to each state so that nicely formated names appear in the action
box for things like "Published (yet to be effective)" rather than
"published_not_yet_effective", and so we can lie about the names
to make them unique, so that "foo_workflow_pending" looks like
"Pending". In the second instance, I see no reason why the state
variable name change action shouldn't migrate the value of the old
state variable to the new for all the content managed by this
workflow, and it could probably automatically add indexes for
new state variable names if they don't already exists (and
perhaps remove indexes for state variable names not used elsewhere).
While we're thinking about ways to make sweeping workflow changes
less painful, there are a couple of changes that could be made
to the code that changes content type to workflow mappings: if a
content to workflow mapping has changed, then, for each instance of
that content type, attempt to keep the state variable the same
unless that state doesn't exist in the new workflow, then evaluate
any automatic transitions on that state. This way it's possible
to migrate between workflows by ensuring that states with the same
name have the same semantics, or if they don't exists in the new
workflow, we can create placeholder states with an automatic
transition to the state we want to be in.
]
Scripts Tab
Scripts are used to extend the workflow in various ways. Scripts can
be External Methods, Python Scripts, DTML methods, or any other callable
Zope object. They are accessible by name in expressions, eg::
scripts/myScript
or::
python:scripts.myScript(arg1, arg2...)
From transitions, as before and after scripts, they are invoked with a
'state_change' object as the first argument; see the Expressions section
for more details on the 'state_change' object.
Objects under the scripts are managed in the usual ZMI fashion.
Permissions Tab
You can manage all of the actions a user can perform on an object by
setting up permissions to be managed by the workflow under the
permissions tab. Here, you can select which permissions should be
state-dependent from a list of all available permissions, and you
can delete previously selected permissions. In each state, use
it's permissions tab to set up the role to permission mappings
appropriate for that state.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment