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