|
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
3 # |
|
4 # This file is part of CubicWeb. |
|
5 # |
|
6 # CubicWeb is free software: you can redistribute it and/or modify it under the |
|
7 # terms of the GNU Lesser General Public License as published by the Free |
|
8 # Software Foundation, either version 2.1 of the License, or (at your option) |
|
9 # any later version. |
|
10 # |
|
11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT |
|
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
13 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
|
14 # details. |
|
15 # |
|
16 # You should have received a copy of the GNU Lesser General Public License along |
|
17 # with CubicWeb. If not, see <http://www.gnu.org/licenses/>. |
|
18 """workflow related schemas |
|
19 |
|
20 """ |
|
21 __docformat__ = "restructuredtext en" |
|
22 from cubicweb import _ |
|
23 |
|
24 from yams.buildobjs import (EntityType, RelationType, RelationDefinition, |
|
25 SubjectRelation, |
|
26 RichString, String, Int) |
|
27 from cubicweb.schema import RQLConstraint |
|
28 from cubicweb.schemas import (PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS, |
|
29 RO_REL_PERMS) |
|
30 |
|
31 class Workflow(EntityType): |
|
32 __permissions__ = PUB_SYSTEM_ENTITY_PERMS |
|
33 |
|
34 name = String(required=True, indexed=True, internationalizable=True, |
|
35 maxsize=256) |
|
36 description = RichString(default_format='text/rest', |
|
37 description=_('semantic description of this workflow')) |
|
38 |
|
39 workflow_of = SubjectRelation('CWEType', cardinality='+*', |
|
40 description=_('entity types which may use this workflow'), |
|
41 constraints=[RQLConstraint('O final FALSE')]) |
|
42 |
|
43 initial_state = SubjectRelation('State', cardinality='?*', |
|
44 constraints=[RQLConstraint('O state_of S', |
|
45 msg=_('state doesn\'t belong to this workflow'))], |
|
46 description=_('initial state for this workflow')) |
|
47 |
|
48 |
|
49 class default_workflow(RelationType): |
|
50 """default workflow for an entity type""" |
|
51 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
52 |
|
53 subject = 'CWEType' |
|
54 object = 'Workflow' |
|
55 cardinality = '?*' |
|
56 constraints = [RQLConstraint('S final FALSE, O workflow_of S', |
|
57 msg=_('workflow isn\'t a workflow for this type'))] |
|
58 |
|
59 |
|
60 class State(EntityType): |
|
61 """used to associate simple states to an entity type and/or to define |
|
62 workflows |
|
63 """ |
|
64 __permissions__ = PUB_SYSTEM_ENTITY_PERMS |
|
65 __unique_together__ = [('name', 'state_of')] |
|
66 name = String(required=True, indexed=True, internationalizable=True, maxsize=256) |
|
67 description = RichString(default_format='text/rest', |
|
68 description=_('semantic description of this state')) |
|
69 |
|
70 # XXX should be on BaseTransition w/ AND/OR selectors when we will |
|
71 # implements #345274 |
|
72 allowed_transition = SubjectRelation('BaseTransition', cardinality='**', |
|
73 constraints=[RQLConstraint('S state_of WF, O transition_of WF', |
|
74 msg=_('state and transition don\'t belong the the same workflow'))], |
|
75 description=_('allowed transitions from this state')) |
|
76 state_of = SubjectRelation('Workflow', cardinality='1*', composite='object', inlined=True, |
|
77 description=_('workflow to which this state belongs')) |
|
78 |
|
79 |
|
80 class BaseTransition(EntityType): |
|
81 """abstract base class for transitions""" |
|
82 __permissions__ = PUB_SYSTEM_ENTITY_PERMS |
|
83 __unique_together__ = [('name', 'transition_of')] |
|
84 |
|
85 name = String(required=True, indexed=True, internationalizable=True, maxsize=256) |
|
86 type = String(vocabulary=(_('normal'), _('auto')), default='normal') |
|
87 description = RichString(description=_('semantic description of this transition')) |
|
88 |
|
89 transition_of = SubjectRelation('Workflow', cardinality='1*', composite='object', inlined=True, |
|
90 description=_('workflow to which this transition belongs')) |
|
91 |
|
92 |
|
93 class require_group(RelationDefinition): |
|
94 """group in which a user should be to be allowed to pass this transition""" |
|
95 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
96 subject = 'BaseTransition' |
|
97 object = 'CWGroup' |
|
98 |
|
99 |
|
100 class condition(RelationDefinition): |
|
101 """a RQL expression which should return some results, else the transition |
|
102 won't be available. |
|
103 |
|
104 This query may use X and U variables that will respectivly represents the |
|
105 current entity and the current user. |
|
106 """ |
|
107 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
108 subject = 'BaseTransition' |
|
109 object = 'RQLExpression' |
|
110 cardinality = '*?' |
|
111 composite = 'subject' |
|
112 |
|
113 |
|
114 class Transition(BaseTransition): |
|
115 """use to define a transition from one or multiple states to a destination |
|
116 states in workflow's definitions. Transition without destination state will |
|
117 go back to the state from which we arrived to the current state. |
|
118 """ |
|
119 __specializes_schema__ = True |
|
120 |
|
121 destination_state = SubjectRelation( |
|
122 'State', cardinality='?*', |
|
123 constraints=[RQLConstraint('S transition_of WF, O state_of WF', |
|
124 msg=_('state and transition don\'t belong the the same workflow'))], |
|
125 description=_('destination state for this transition')) |
|
126 |
|
127 |
|
128 class WorkflowTransition(BaseTransition): |
|
129 """special transition allowing to go through a sub-workflow""" |
|
130 __specializes_schema__ = True |
|
131 |
|
132 subworkflow = SubjectRelation('Workflow', cardinality='1*', |
|
133 constraints=[RQLConstraint('S transition_of WF, WF workflow_of ET, O workflow_of ET', |
|
134 msg=_('subworkflow isn\'t a workflow for the same types as the transition\'s workflow'))] |
|
135 ) |
|
136 # XXX use exit_of and inline it |
|
137 subworkflow_exit = SubjectRelation('SubWorkflowExitPoint', cardinality='*1', |
|
138 composite='subject') |
|
139 |
|
140 |
|
141 class SubWorkflowExitPoint(EntityType): |
|
142 """define how we get out from a sub-workflow""" |
|
143 subworkflow_state = SubjectRelation( |
|
144 'State', cardinality='1*', |
|
145 constraints=[RQLConstraint('T subworkflow_exit S, T subworkflow WF, O state_of WF', |
|
146 msg=_('exit state must be a subworkflow state'))], |
|
147 description=_('subworkflow state')) |
|
148 destination_state = SubjectRelation( |
|
149 'State', cardinality='?*', |
|
150 constraints=[RQLConstraint('T subworkflow_exit S, T transition_of WF, O state_of WF', |
|
151 msg=_('destination state must be in the same workflow as our parent transition'))], |
|
152 description=_('destination state. No destination state means that transition ' |
|
153 'should go back to the state from which we\'ve entered the ' |
|
154 'subworkflow.')) |
|
155 |
|
156 |
|
157 class TrInfo(EntityType): |
|
158 """workflow history item""" |
|
159 # 'add' security actually done by hooks |
|
160 __permissions__ = { |
|
161 'read': ('managers', 'users', 'guests',), # XXX U has_read_permission O ? |
|
162 'add': ('managers', 'users', 'guests',), |
|
163 'delete': (), # XXX should we allow managers to delete TrInfo? |
|
164 'update': ('managers', 'owners',), |
|
165 } |
|
166 # The unique_together constraint ensures that 2 repositories |
|
167 # sharing the db won't be able to fire a transition simultaneously |
|
168 # on the same entity tr_count is filled in the FireTransitionHook |
|
169 # to the number of TrInfo attached to the entity on which we |
|
170 # attempt to fire a transition. In other word, it contains the |
|
171 # rank of the TrInfo for that entity, and the constraint says we |
|
172 # cannot have 2 TrInfo with the same rank. |
|
173 __unique_together__ = [('tr_count', 'wf_info_for')] |
|
174 from_state = SubjectRelation('State', cardinality='1*', inlined=True) |
|
175 to_state = SubjectRelation('State', cardinality='1*', inlined=True) |
|
176 # make by_transition optional because we want to allow managers to set |
|
177 # entity into an arbitrary state without having to respect wf transition |
|
178 by_transition = SubjectRelation('BaseTransition', cardinality='?*') |
|
179 comment = RichString(fulltextindexed=True, default_format='text/plain') |
|
180 tr_count = Int(description='autocomputed attribute used to ensure transition coherency') |
|
181 # get actor and date time using owned_by and creation_date |
|
182 |
|
183 class from_state(RelationType): |
|
184 __permissions__ = RO_REL_PERMS.copy() |
|
185 inlined = True |
|
186 |
|
187 class to_state(RelationType): |
|
188 __permissions__ = RO_REL_PERMS.copy() |
|
189 inlined = True |
|
190 |
|
191 class by_transition(RelationType): |
|
192 # 'add' security actually done by hooks |
|
193 __permissions__ = { |
|
194 'read': ('managers', 'users', 'guests',), |
|
195 'add': ('managers', 'users', 'guests',), |
|
196 'delete': (), |
|
197 } |
|
198 inlined = True |
|
199 |
|
200 |
|
201 class workflow_of(RelationType): |
|
202 """link a workflow to one or more entity type""" |
|
203 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
204 |
|
205 class state_of(RelationType): |
|
206 """link a state to one or more workflow""" |
|
207 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
208 inlined = True |
|
209 |
|
210 class transition_of(RelationType): |
|
211 """link a transition to one or more workflow""" |
|
212 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
213 inlined = True |
|
214 |
|
215 class destination_state(RelationType): |
|
216 """destination state of a transition""" |
|
217 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
218 inlined = True |
|
219 |
|
220 class allowed_transition(RelationType): |
|
221 """allowed transitions from this state""" |
|
222 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
223 |
|
224 class initial_state(RelationType): |
|
225 """indicate which state should be used by default when an entity using |
|
226 states is created |
|
227 """ |
|
228 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
229 inlined = True |
|
230 |
|
231 |
|
232 class subworkflow(RelationType): |
|
233 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
234 inlined = True |
|
235 |
|
236 class exit_point(RelationType): |
|
237 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
238 |
|
239 class subworkflow_state(RelationType): |
|
240 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
241 inlined = True |
|
242 |
|
243 |
|
244 # "abstract" relations, set by WorkflowableEntityType ########################## |
|
245 |
|
246 class custom_workflow(RelationType): |
|
247 """allow to set a specific workflow for an entity""" |
|
248 __permissions__ = PUB_SYSTEM_REL_PERMS |
|
249 |
|
250 cardinality = '?*' |
|
251 constraints = [RQLConstraint('S is ET, O workflow_of ET', |
|
252 msg=_('workflow isn\'t a workflow for this type'))] |
|
253 object = 'Workflow' |
|
254 |
|
255 |
|
256 class wf_info_for(RelationType): |
|
257 """link a transition information to its object""" |
|
258 # 'add' security actually done by hooks |
|
259 __permissions__ = { |
|
260 'read': ('managers', 'users', 'guests',), |
|
261 'add': ('managers', 'users', 'guests',), |
|
262 'delete': (), |
|
263 } |
|
264 inlined = True |
|
265 |
|
266 cardinality = '1*' |
|
267 composite = 'object' |
|
268 fulltext_container = composite |
|
269 subject = 'TrInfo' |
|
270 |
|
271 |
|
272 class in_state(RelationType): |
|
273 """indicate the current state of an entity""" |
|
274 __permissions__ = RO_REL_PERMS |
|
275 |
|
276 # not inlined intentionnally since when using ldap sources, user'state |
|
277 # has to be stored outside the CWUser table |
|
278 inlined = False |
|
279 |
|
280 cardinality = '1*' |
|
281 constraints = [RQLConstraint('S is ET, O state_of WF, WF workflow_of ET', |
|
282 msg=_('state doesn\'t apply to this entity\'s type'))] |
|
283 object = 'State' |