doc/book/en/development/datamodel/define-workflows.rst
author Julien Jehannet <julien.jehannet@logilab.fr>
Tue, 07 Jul 2009 12:01:39 +0200
branchstable
changeset 2307 060c3f3f7d28
parent 2175 16d3c37c5d28
child 2476 1294a6bdf3bf
permissions -rw-r--r--
fix documentation build
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     1
.. -*- coding: utf-8 -*-
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     2
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     3
.. _Workflow:
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     4
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     5
An Example: Workflow definition
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     6
===============================
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     7
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     8
General
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
     9
-------
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    10
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    11
A workflow describes how certain entities have to evolve between
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    12
different states. Hence we have a set of states, and a "transition graph",
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    13
i.e. a list of possible transitions from one state to another state.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    14
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    15
We will define a simple workflow for a blog, with only the following
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    16
two states: `submitted` and `published`. So first, we create a simple
2175
16d3c37c5d28 [doc] improvements
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2172
diff changeset
    17
*CubicWeb* in ten minutes (see :ref:`BlogFiveMinutes`).
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    18
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    19
Set-up a workflow
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    20
-----------------
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    21
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    22
We want to create a workflow to control the quality of the BlogEntry
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    23
submitted on your application. When a BlogEntry is created by a user
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    24
its state should be `submitted`. To be visible to all, it has to
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    25
be in the state `published`. To move it from `submitted` to `published`,
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    26
we need a transition that we can call `approve_blogentry`.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    27
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    28
A BlogEntry state should not be modifiable by every user.
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    29
So we have to define a group of users, `moderators`, and
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    30
this group will have appropriate permissions to publish a BlogEntry.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    31
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    32
There are two ways to create a workflow: from the user interface,
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    33
or by defining it in ``migration/postcreate.py``.
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    34
This script is executed each time a new ``cubicweb-ctl db-init`` is done.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    35
We strongly recommand to create the workflow in ``migration/postcreate.py``
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    36
and we will now show you how. Read `Under the hood`_ to understand why.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    37
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    38
Update the schema
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    39
~~~~~~~~~~~~~~~~~
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    40
If we want a State for our BlogEntry, we have to define a relation
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    41
``in_state`` in the schema of BlogEntry. So we add
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    42
the line ``in_state (...)``::
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    43
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    44
  class BlogEntry(EntityType):
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    45
      title = String(maxsize=100, required=True)
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    46
      publish_date = Date(default='TODAY')
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    47
      text_format = String(meta=True, internationalizable=True, maxsize=50,
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    48
                           default='text/rest', constraints=[format_constraint])
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    49
      text = String(fulltextindexed=True)
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    50
      category = String(vocabulary=('important','business'))
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    51
      entry_of = SubjectRelation('Blog', cardinality='?*')
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    52
      in_state = SubjectRelation('State', cardinality='1*')
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    53
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    54
As you updated the schema, you have to re-execute ``cubicweb-ctl db-init``
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    55
to initialize the database and migrate your existing entities.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    56
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    57
[WRITE ABOUT MIGRATION]
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    58
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    59
Create states, transitions and group permissions
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    60
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    61
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    62
The ``postcreate.py`` script is executed in a special environment, adding
2175
16d3c37c5d28 [doc] improvements
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2172
diff changeset
    63
several *CubicWeb* primitives that can be used.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    64
They are all defined in the ``class ServerMigrationHelper``.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    65
We will only discuss the methods we use to create a workflow in this example.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    66
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    67
To define our workflow for BlogDemo, please add the following lines
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    68
to ``migration/postcreate.py``::
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    69
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    70
  _ = unicode
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    71
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    72
  moderators = add_entity('CWGroup', name=u"moderators")
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    73
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    74
This adds the `moderators` user group.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    75
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    76
::
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    77
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    78
  submitted = add_state(_('submitted'), 'BlogEntry', initial=True)
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    79
  published = add_state(_('published'), 'BlogEntry')
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    80
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    81
``add_state`` expects as first argument the name of the state you want
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    82
to create, then the entity type on which the state can be applied,
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    83
and an optional argument to say if it is supposed to be the initial state
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    84
of the entity type.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    85
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    86
::
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    87
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    88
  add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),)
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    89
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    90
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    91
``add_transition`` expects
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    92
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    93
  * as the first argument the name of the
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    94
    transition, then the entity type on which the transition can be applied,
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    95
  * then the list of states on which the transition can be trigged,
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
    96
  * the target state of the transition,
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    97
  * and the permissions
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    98
    (e.g. a list of user groups who can apply the transition; the user
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
    99
    has to belong to at least one of the listed group to perform the action).
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   100
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   101
::
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   102
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   103
  checkpoint()
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   104
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   105
.. note::
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   106
  Do not forget to add the `_()` in front of all states and transitions names while creating
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   107
  a workflow so that they will be identified by the i18n catalog scripts.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   108
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   109
In addition to the user group condition, we could have added a RQL condition.
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   110
In this case, the user can only perform the action if
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   111
the two conditions are satisfied.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   112
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   113
If we use a RQL condition on a transition, we can use the following
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   114
variables:
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   115
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   116
* `%(eid)s`, object's eid
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   117
* `%(ueid)s`, user executing the query eid
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   118
* `%(seid)s`, the object's current state eid
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   119
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   120
2307
060c3f3f7d28 fix documentation build
Julien Jehannet <julien.jehannet@logilab.fr>
parents: 2175
diff changeset
   121
.. image:: ../../images/lax-book.03-transitions-view.en.png
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   122
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   123
You can notice that in the action box of a BlogEntry, the state
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   124
is now listed as well as the possible transitions defined by the workflow.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   125
The transitions will only be displayed for users having the right permissions.
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   126
In our example, the transition `approve_blogentry` will only be displayed
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   127
for the users belonging to the group `moderators` or `managers`.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   128
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   129
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   130
Under the hood
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   131
~~~~~~~~~~~~~~
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   132
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   133
A workflow is a collection of entities of type ``State`` and of type ``Transition``
2175
16d3c37c5d28 [doc] improvements
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 2172
diff changeset
   134
which are standard *CubicWeb* entity types.
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   135
For instance, the following lines::
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   136
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   137
  submitted = add_state(_('submitted'), 'BlogEntry', initial=True)
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   138
  published = add_state(_('published'), 'BlogEntry')
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   139
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   140
will create two entities of type ``State``, one with name 'submitted', and the other
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   141
with name 'published'. Whereas::
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   142
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   143
  add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),)
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   144
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   145
will create an entity of type ``Transition`` with name 'approve_blogentry' which will
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   146
be linked to the ``State`` entities created before.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   147
As a consequence, we could use the administration interface to do these operations.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   148
But it is not recommanded because it will be uselessly complicated
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   149
and will be only local to your instance.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   150
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   151
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   152
Indeed, if you create the states and transitions through the user interface,
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   153
next time you initialize the database
2172
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   154
you will have to re-create all the entities.
cf8f9180e63e delete-trailing-whitespace
Nicolas Chauvat <nicolas.chauvat@logilab.fr>
parents: 1714
diff changeset
   155
The user interface should only be a reference for you to view the states
1714
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   156
and transitions, but is not the appropriate interface to define your
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   157
application workflow.
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   158
a721966779be new book layout, do not compile yet
sylvain.thenault@logilab.fr
parents:
diff changeset
   159