19 |
19 |
20 * entity types defining workflow (Workflow, State, Transition...) |
20 * entity types defining workflow (Workflow, State, Transition...) |
21 * workflow history (TrInfo) |
21 * workflow history (TrInfo) |
22 * adapter for workflowable entities (IWorkflowableAdapter) |
22 * adapter for workflowable entities (IWorkflowableAdapter) |
23 """ |
23 """ |
24 from __future__ import print_function |
|
25 |
|
26 |
|
27 |
|
28 from six import text_type, string_types |
|
29 |
|
30 from logilab.common.decorators import cached, clear_cache |
24 from logilab.common.decorators import cached, clear_cache |
31 |
25 |
32 from cubicweb.entities import AnyEntity, fetch_config |
26 from cubicweb.entities import AnyEntity, fetch_config |
33 from cubicweb.view import EntityAdapter |
27 from cubicweb.view import EntityAdapter |
34 from cubicweb.predicates import relation_possible |
28 from cubicweb.predicates import relation_possible |
96 return None |
90 return None |
97 |
91 |
98 def transition_by_name(self, trname): |
92 def transition_by_name(self, trname): |
99 rset = self._cw.execute('Any T, TN WHERE T name TN, T name %(n)s, ' |
93 rset = self._cw.execute('Any T, TN WHERE T name TN, T name %(n)s, ' |
100 'T transition_of WF, WF eid %(wf)s', |
94 'T transition_of WF, WF eid %(wf)s', |
101 {'n': text_type(trname), 'wf': self.eid}) |
95 {'n': trname, 'wf': self.eid}) |
102 if rset: |
96 if rset: |
103 return rset.get_entity(0, 0) |
97 return rset.get_entity(0, 0) |
104 return None |
98 return None |
105 |
99 |
106 def transition_by_eid(self, eid): |
100 def transition_by_eid(self, eid): |
113 |
107 |
114 # wf construction methods ################################################## |
108 # wf construction methods ################################################## |
115 |
109 |
116 def add_state(self, name, initial=False, **kwargs): |
110 def add_state(self, name, initial=False, **kwargs): |
117 """add a state to this workflow""" |
111 """add a state to this workflow""" |
118 state = self._cw.create_entity('State', name=text_type(name), **kwargs) |
112 state = self._cw.create_entity('State', name=name, **kwargs) |
119 self._cw.execute('SET S state_of WF WHERE S eid %(s)s, WF eid %(wf)s', |
113 self._cw.execute('SET S state_of WF WHERE S eid %(s)s, WF eid %(wf)s', |
120 {'s': state.eid, 'wf': self.eid}) |
114 {'s': state.eid, 'wf': self.eid}) |
121 if initial: |
115 if initial: |
122 assert not self.initial, "Initial state already defined as %s" % self.initial |
116 assert not self.initial, "Initial state already defined as %s" % self.initial |
123 self._cw.execute('SET WF initial_state S ' |
117 self._cw.execute('SET WF initial_state S ' |
125 {'s': state.eid, 'wf': self.eid}) |
119 {'s': state.eid, 'wf': self.eid}) |
126 return state |
120 return state |
127 |
121 |
128 def _add_transition(self, trtype, name, fromstates, |
122 def _add_transition(self, trtype, name, fromstates, |
129 requiredgroups=(), conditions=(), **kwargs): |
123 requiredgroups=(), conditions=(), **kwargs): |
130 tr = self._cw.create_entity(trtype, name=text_type(name), **kwargs) |
124 tr = self._cw.create_entity(trtype, name=name, **kwargs) |
131 self._cw.execute('SET T transition_of WF ' |
125 self._cw.execute('SET T transition_of WF ' |
132 'WHERE T eid %(t)s, WF eid %(wf)s', |
126 'WHERE T eid %(t)s, WF eid %(wf)s', |
133 {'t': tr.eid, 'wf': self.eid}) |
127 {'t': tr.eid, 'wf': self.eid}) |
134 assert fromstates, fromstates |
128 assert fromstates, fromstates |
135 if not isinstance(fromstates, (tuple, list)): |
129 if not isinstance(fromstates, (tuple, list)): |
255 self._cw.execute('DELETE T condition R WHERE T eid %(x)s', |
249 self._cw.execute('DELETE T condition R WHERE T eid %(x)s', |
256 {'x': self.eid}) |
250 {'x': self.eid}) |
257 for gname in requiredgroups: |
251 for gname in requiredgroups: |
258 rset = self._cw.execute('SET T require_group G ' |
252 rset = self._cw.execute('SET T require_group G ' |
259 'WHERE T eid %(x)s, G name %(gn)s', |
253 'WHERE T eid %(x)s, G name %(gn)s', |
260 {'x': self.eid, 'gn': text_type(gname)}) |
254 {'x': self.eid, 'gn': gname}) |
261 assert rset, '%s is not a known group' % gname |
255 assert rset, '%s is not a known group' % gname |
262 if isinstance(conditions, string_types): |
256 if isinstance(conditions, str): |
263 conditions = (conditions,) |
257 conditions = (conditions,) |
264 for expr in conditions: |
258 for expr in conditions: |
265 if isinstance(expr, string_types): |
259 if isinstance(expr, str): |
266 kwargs = {'expr': text_type(expr)} |
260 kwargs = {'expr': expr} |
267 else: |
261 else: |
268 assert isinstance(expr, dict) |
262 assert isinstance(expr, dict) |
269 kwargs = expr |
263 kwargs = expr |
270 kwargs['x'] = self.eid |
264 kwargs['x'] = self.eid |
271 kwargs.setdefault('mainvars', u'X') |
265 kwargs.setdefault('mainvars', u'X') |
413 @cached |
407 @cached |
414 def cwetype_workflow(self): |
408 def cwetype_workflow(self): |
415 """return the default workflow for entities of this type""" |
409 """return the default workflow for entities of this type""" |
416 # XXX CWEType method |
410 # XXX CWEType method |
417 wfrset = self._cw.execute('Any WF WHERE ET default_workflow WF, ' |
411 wfrset = self._cw.execute('Any WF WHERE ET default_workflow WF, ' |
418 'ET name %(et)s', {'et': text_type(self.entity.cw_etype)}) |
412 'ET name %(et)s', {'et': self.entity.cw_etype}) |
419 if wfrset: |
413 if wfrset: |
420 return wfrset.get_entity(0, 0) |
414 return wfrset.get_entity(0, 0) |
421 self.warning("can't find any workflow for %s", self.entity.cw_etype) |
415 self.warning("can't find any workflow for %s", self.entity.cw_etype) |
422 return None |
416 return None |
423 |
417 |
478 return |
472 return |
479 rset = self._cw.execute( |
473 rset = self._cw.execute( |
480 'Any T,TT, TN WHERE S allowed_transition T, S eid %(x)s, ' |
474 'Any T,TT, TN WHERE S allowed_transition T, S eid %(x)s, ' |
481 'T type TT, T type %(type)s, ' |
475 'T type TT, T type %(type)s, ' |
482 'T name TN, T transition_of WF, WF eid %(wfeid)s', |
476 'T name TN, T transition_of WF, WF eid %(wfeid)s', |
483 {'x': self.current_state.eid, 'type': text_type(type), |
477 {'x': self.current_state.eid, 'type': type, |
484 'wfeid': self.current_workflow.eid}) |
478 'wfeid': self.current_workflow.eid}) |
485 for tr in rset.entities(): |
479 for tr in rset.entities(): |
486 if tr.may_be_fired(self.entity.eid): |
480 if tr.may_be_fired(self.entity.eid): |
487 yield tr |
481 yield tr |
488 |
482 |
527 kwargs['to_state'] = self._cw.entity_from_eid(tseid) |
521 kwargs['to_state'] = self._cw.entity_from_eid(tseid) |
528 return self._cw.create_entity('TrInfo', **kwargs) |
522 return self._cw.create_entity('TrInfo', **kwargs) |
529 |
523 |
530 def _get_transition(self, tr): |
524 def _get_transition(self, tr): |
531 assert self.current_workflow |
525 assert self.current_workflow |
532 if isinstance(tr, string_types): |
526 if isinstance(tr, str): |
533 _tr = self.current_workflow.transition_by_name(tr) |
527 _tr = self.current_workflow.transition_by_name(tr) |
534 assert _tr is not None, 'not a %s transition: %s' % ( |
528 assert _tr is not None, 'not a %s transition: %s' % ( |
535 self.__regid__, tr) |
529 self.__regid__, tr) |
536 tr = _tr |
530 tr = _tr |
537 return tr |
531 return tr |