3 .. _Workflow: |
3 .. _Workflow: |
4 |
4 |
5 Workflow definition |
5 Workflow definition |
6 =================== |
6 =================== |
7 |
7 |
|
8 [TODO : All this is too obscure and often not very understandable...] |
|
9 |
8 General |
10 General |
9 ------- |
11 ------- |
10 |
12 |
11 A workflow can be defined in a `CubicWeb` application thanks to the system |
13 [XXX define what a "Workflow" is: states, transitions, transition graph ] |
12 entities ``State`` and ``Transition``. Those are defined within all |
|
13 `CubicWeb` application and can be set-up through the main administrator interface. |
|
14 |
|
15 Once your schema is defined, you can start creating the set of states and |
|
16 the required transitions for your applications entities. |
|
17 |
|
18 You first need to define the states and then the transitions between those |
|
19 to complete your workflow. |
|
20 |
|
21 A ``State`` defines the status of an entity. While creating a new state, |
|
22 you will be first given the option to select the entity type the state |
|
23 can be applied to. By choosing ``Apply``, a new section will be displayed |
|
24 in the editing screen to enable you to add relation to the state you are |
|
25 creating. |
|
26 |
|
27 A ``Transition`` is also based on an entity type it can be applied to. |
|
28 By choosing ``Apply``, a new section will be displayed in the editing |
|
29 screen to enable you to add relation to the transition you are |
|
30 creating. |
|
31 |
|
32 At the transition level you will also define the group of user which can |
|
33 aplly this transition to an object. |
|
34 |
|
35 |
14 |
36 Example of a simple workflow |
15 Example of a simple workflow |
37 ---------------------------- |
16 ---------------------------- |
38 |
17 |
39 Please see the tutorial to view and example of a simple workflow. |
18 Please see the tutorial to view an example of a simple workflow. |
40 |
19 |
41 |
20 |
42 [Create a simple workflow for BlogDemo, to have a moderator approve new blog |
21 [Create a simple workflow for BlogDemo, to have a moderator approve new blog |
43 entry to be published. This implies, specify a dedicated group of blog |
22 entry to be published. This implies specifying a dedicated group of blog |
44 moderator as well as hide the view of a blog entry to the user until |
23 moderator as well as hiding the view of a blog entry to the user until |
45 it reaches the state published] |
24 it reaches the state published] |
46 |
25 |
47 Set-up a workflow |
26 Set-up a workflow |
48 ----------------- |
27 ----------------- |
49 |
28 |
50 We want to create a workflow to control the quality of the BlogEntry |
29 We want to create a workflow to control the quality of the BlogEntry |
51 submitted on your application. When a BlogEntry is created by a user |
30 submitted on your application. When a BlogEntry is created by a user |
52 its state should be `submitted`. To be visible to all, it needs to |
31 its state should be `submitted`. To be visible to all, it has to |
53 be in the state `published`. To move from `submitted` to `published` |
32 be in the state `published`. To move it from `submitted` to `published`, |
54 we need a transition that we can name `approve_blogentry`. |
33 we need a transition that we can call `approve_blogentry`. |
55 |
34 |
56 We do not want every user to be allowed to change the state of a |
35 A BlogEntry state should not be modifiable by every user. |
57 BlogEntry. We need to define a group of user, `moderators`, and |
36 So we have to define a group of users, `moderators`, and |
58 this group will have appropriate permissions to approve BlogEntry |
37 this group will have appropriate permissions to publish a BlogEntry. |
59 to be published and visible to all. |
|
60 |
38 |
61 There are two ways to create a workflow, form the user interface, |
39 There are two ways to create a workflow: from the user interface, |
62 and also by defining it in ``migration/postcreate.py``. |
40 or by defining it in ``migration/postcreate.py``. |
63 This script is executed each time a new ``cubicweb-ctl db-init`` is done. |
41 This script is executed each time a new ``cubicweb-ctl db-init`` is done. |
64 If you create the states and transitions through the user interface |
42 We strongly recommand to create the workflow in ``migration/postcreate.py`` |
65 this means that next time you will need to initialize the database |
43 and we will now show you how. Read `Under the hood`_ to understand why. |
66 you will have to re-create all the entities. |
|
67 We strongly recommand you create the workflow in ``migration\postcreate.py`` |
|
68 and we will now show you how. |
|
69 The user interface would only be a reference for you to view the states |
|
70 and transitions but is not the appropriate interface to define your |
|
71 application workflow. |
|
72 |
44 |
73 Update the schema |
45 Update the schema |
74 ~~~~~~~~~~~~~~~~~ |
46 ~~~~~~~~~~~~~~~~~ |
75 To enable a BlogEntry to have a State, we have to define a relation |
47 If we want a State for our BlogEntry, we have to define a relation |
76 ``in_state`` in the schema of BlogEntry. Please do as follows, add |
48 ``in_state`` in the schema of BlogEntry. So we add |
77 the line ``in_state (...)``:: |
49 the line ``in_state (...)``:: |
78 |
50 |
79 class BlogEntry(EntityType): |
51 class BlogEntry(EntityType): |
80 title = String(maxsize=100, required=True) |
52 title = String(maxsize=100, required=True) |
81 publish_date = Date(default='TODAY') |
53 publish_date = Date(default='TODAY') |
84 text = String(fulltextindexed=True) |
56 text = String(fulltextindexed=True) |
85 category = String(vocabulary=('important','business')) |
57 category = String(vocabulary=('important','business')) |
86 entry_of = SubjectRelation('Blog', cardinality='?*') |
58 entry_of = SubjectRelation('Blog', cardinality='?*') |
87 in_state = SubjectRelation('State', cardinality='1*') |
59 in_state = SubjectRelation('State', cardinality='1*') |
88 |
60 |
89 As you updated the schema, you will have re-execute ``cubicweb-ctl db-init`` |
61 As you updated the schema, you have to re-execute ``cubicweb-ctl db-init`` |
90 to initialize the database and migrate your existing entities. |
62 to initialize the database and migrate your existing entities. |
|
63 |
91 [WRITE ABOUT MIGRATION] |
64 [WRITE ABOUT MIGRATION] |
92 |
65 |
93 Create states, transitions and group permissions |
66 Create states, transitions and group permissions |
94 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
67 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
95 |
68 |
96 At the time the ``postcreate.py`` script is executed, several methods |
69 The ``postcreate.py`` script is executed in a special environment, adding |
97 can be used. They are all defined in the ``class ServerMigrationHelper``. |
70 several `CubicWeb` primitives that can be used. |
98 We will only discuss the method we use to create a wrokflow here. |
71 They are all defined in the ``class ServerMigrationHelper``. |
|
72 We will only discuss the methods we use to create a workflow in this example. |
99 |
73 |
100 To define our workflow for BlogDemo, please add the following lines |
74 To define our workflow for BlogDemo, please add the following lines |
101 to ``migration/postcreate.py``:: |
75 to ``migration/postcreate.py``:: |
102 |
76 |
103 _ = unicode |
77 _ = unicode |
104 |
78 |
105 moderators = add_entity('EGroup', name=u"moderators") |
79 moderators = add_entity('EGroup', name=u"moderators") |
|
80 |
|
81 This adds the `moderators` user group. |
|
82 |
|
83 :: |
106 |
84 |
107 submitted = add_state(_('submitted'), 'BlogEntry', initial=True) |
85 submitted = add_state(_('submitted'), 'BlogEntry', initial=True) |
108 published = add_state(_('published'), 'BlogEntry') |
86 published = add_state(_('published'), 'BlogEntry') |
109 |
87 |
|
88 ``add_state`` expects as first argument the name of the state you want |
|
89 to create, then the entity type on which the state can be applied, |
|
90 and an optional argument to say if it is supposed to be the initial state |
|
91 of the entity type. |
|
92 |
|
93 :: |
|
94 |
110 add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) |
95 add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) |
|
96 |
|
97 |
|
98 ``add_transition`` expects |
|
99 |
|
100 * as the first argument the name of the |
|
101 transition, then the entity type on which the transition can be applied, |
|
102 * then the list of states on which the transition can be trigged, |
|
103 * the target state of the transition, |
|
104 * and the permissions |
|
105 (e.g. a list of user groups who can apply the transition; the user |
|
106 has to belong to at least one of the listed group to perform the action). |
|
107 |
|
108 :: |
111 |
109 |
112 checkpoint() |
110 checkpoint() |
113 |
111 |
114 .. note:: |
112 .. note:: |
115 Do not forget to add the `_()` in front of all states and transitions names while creating |
113 Do not forget to add the `_()` in front of all states and transitions names while creating |
116 a workflow so that they will be identified by the i18n catalog scripts. |
114 a workflow so that they will be identified by the i18n catalog scripts. |
117 |
115 |
118 ``add_entity`` is used here to define the new group of users that we |
116 In addition to the user group condition, we could have added a RQL condition. |
119 need to define the transitions, `moderators`. |
117 In this case, the user can only perform the action if |
120 If this group required by the transition is not defined before the |
118 the two conditions are satisfied. |
121 transition is created, it will not create the relation `transition |
|
122 require the group moderator`. |
|
123 |
|
124 ``add_state`` expects as the first argument the name of the state you are |
|
125 willing to create, then the entity type on which the state can be applied, |
|
126 and an optionnal argument to set if the state is the initial state |
|
127 of the entity type or not. |
|
128 |
|
129 ``add_transition`` expects as the first argument the name of the |
|
130 transition, then the entity type on which we can apply the transition, |
|
131 then the list of possible initial states from which the transition |
|
132 can be applied, the target state of the transition, and the permissions |
|
133 (e.g. list of the groups of users who can apply the transition, the user |
|
134 needs to belong to at least one of the listed group). |
|
135 |
|
136 |
|
137 We could have also added a RQL condition in addition to a group to |
|
138 which the user should belong to. |
|
139 |
|
140 If we use both RQL condition and group, the two must be satisfied |
|
141 for the user to be allowed to apply the transition. |
|
142 |
119 |
143 If we use a RQL condition on a transition, we can use the following |
120 If we use a RQL condition on a transition, we can use the following |
144 variables: |
121 variables: |
145 |
122 |
146 * `%(eid)s`, object's eid |
123 * `%(eid)s`, object's eid |
148 * `%(seid)s`, the object's current state eid |
125 * `%(seid)s`, the object's current state eid |
149 |
126 |
150 |
127 |
151 .. image:: images/lax-book.03-transitions-view.en.png |
128 .. image:: images/lax-book.03-transitions-view.en.png |
152 |
129 |
153 You can now notice that in the actions box of a BlogEntry, the state |
130 You can notice that in the action box of a BlogEntry, the state |
154 is now listed as well as the possible transitions from this state |
131 is now listed as well as the possible transitions defined by the workflow. |
155 defined by the workflow. This transition, as defined in the workflow, |
132 The transitions will only be displayed for users having the right permissions. |
156 will only being displayed for the users belonging to the group |
133 In our example, the transition `approve_blogentry` will only be displayed |
157 moderators of managers. |
134 for the users belonging to the group `moderators` or `managers`. |
|
135 |
|
136 |
|
137 Under the hood |
|
138 ~~~~~~~~~~~~~~ |
|
139 |
|
140 A workflow is a collection of entities of type ``State`` and of type ``Transition`` |
|
141 which are standard `CubicWeb` entity types. |
|
142 For instance, the following lines:: |
|
143 |
|
144 submitted = add_state(_('submitted'), 'BlogEntry', initial=True) |
|
145 published = add_state(_('published'), 'BlogEntry') |
|
146 |
|
147 will create two entities of type ``State``, one with name 'submitted', and the other |
|
148 with name 'published'. Whereas:: |
|
149 |
|
150 add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) |
|
151 |
|
152 will create an entity of type ``Transition`` with name 'approve_blogentry' which will |
|
153 be linked to the ``State`` entities created before. |
|
154 As a consequence, we could use the administration interface to do these operations. |
|
155 But it is not recommanded because it will be uselessly complicated |
|
156 and will be only local to your instance. |
|
157 |
|
158 |
|
159 Indeed, if you create the states and transitions through the user interface, |
|
160 next time you initialize the database |
|
161 you will have to re-create all the entities. |
|
162 The user interface should only be a reference for you to view the states |
|
163 and transitions, but is not the appropriate interface to define your |
|
164 application workflow. |
|
165 |
|
166 |