39 |
39 |
40 # operations ################################################################### |
40 # operations ################################################################### |
41 |
41 |
42 class _SetInitialStateOp(hook.Operation): |
42 class _SetInitialStateOp(hook.Operation): |
43 """make initial state be a default state""" |
43 """make initial state be a default state""" |
44 entity = None # make pylint happy |
44 eid = None # make pylint happy |
45 |
45 |
46 def precommit_event(self): |
46 def precommit_event(self): |
47 cnx = self.cnx |
47 cnx = self.cnx |
48 entity = self.entity |
48 entity = cnx.entity_from_eid(self.eid) |
49 iworkflowable = entity.cw_adapt_to('IWorkflowable') |
49 iworkflowable = entity.cw_adapt_to('IWorkflowable') |
50 # if there is an initial state and the entity's state is not set, |
50 # if there is an initial state and the entity's state is not set, |
51 # use the initial state as a default state |
51 # use the initial state as a default state |
52 if not (cnx.deleted_in_transaction(entity.eid) or entity.in_state) \ |
52 if not (cnx.deleted_in_transaction(entity.eid) or entity.in_state) \ |
53 and iworkflowable.current_workflow: |
53 and iworkflowable.current_workflow: |
54 state = iworkflowable.current_workflow.initial |
54 state = iworkflowable.current_workflow.initial |
55 if state: |
55 if state: |
56 cnx.add_relation(entity.eid, 'in_state', state.eid) |
56 cnx.add_relation(self.eid, 'in_state', state.eid) |
57 _FireAutotransitionOp(cnx, entity=entity) |
57 _FireAutotransitionOp(cnx, eid=self.eid) |
58 |
58 |
59 class _FireAutotransitionOp(hook.Operation): |
59 class _FireAutotransitionOp(hook.Operation): |
60 """try to fire auto transition after state changes""" |
60 """try to fire auto transition after state changes""" |
61 entity = None # make pylint happy |
61 eid = None # make pylint happy |
62 |
62 |
63 def precommit_event(self): |
63 def precommit_event(self): |
64 entity = self.entity |
64 entity = self.cnx.entity_from_eid(self.eid) |
65 iworkflowable = entity.cw_adapt_to('IWorkflowable') |
65 iworkflowable = entity.cw_adapt_to('IWorkflowable') |
66 autotrs = list(iworkflowable.possible_transitions('auto')) |
66 autotrs = list(iworkflowable.possible_transitions('auto')) |
67 if autotrs: |
67 if autotrs: |
68 assert len(autotrs) == 1 |
68 assert len(autotrs) == 1 |
69 iworkflowable.fire_transition(autotrs[0]) |
69 iworkflowable.fire_transition(autotrs[0]) |
96 # if there are no history, simply go to new workflow's initial state |
96 # if there are no history, simply go to new workflow's initial state |
97 if not iworkflowable.workflow_history: |
97 if not iworkflowable.workflow_history: |
98 if iworkflowable.current_state.eid != deststate.eid: |
98 if iworkflowable.current_state.eid != deststate.eid: |
99 _change_state(cnx, entity.eid, |
99 _change_state(cnx, entity.eid, |
100 iworkflowable.current_state.eid, deststate.eid) |
100 iworkflowable.current_state.eid, deststate.eid) |
101 _FireAutotransitionOp(cnx, entity=entity) |
101 _FireAutotransitionOp(cnx, eid=entity.eid) |
102 return |
102 return |
103 msg = cnx._('workflow changed to "%s"') |
103 msg = cnx._('workflow changed to "%s"') |
104 msg %= cnx._(mainwf.name) |
104 msg %= cnx._(mainwf.name) |
105 cnx.transaction_data[(entity.eid, 'customwf')] = self.wfeid |
105 cnx.transaction_data[(entity.eid, 'customwf')] = self.wfeid |
106 iworkflowable.change_state(deststate, msg, u'text/plain') |
106 iworkflowable.change_state(deststate, msg, u'text/plain') |
118 raise validation_error(self.treid, {('subworkflow_exit', 'subject'): msg}) |
118 raise validation_error(self.treid, {('subworkflow_exit', 'subject'): msg}) |
119 outputs.add(ep.subwf_state.eid) |
119 outputs.add(ep.subwf_state.eid) |
120 |
120 |
121 |
121 |
122 class _SubWorkflowExitOp(hook.Operation): |
122 class _SubWorkflowExitOp(hook.Operation): |
123 forentity = trinfo = None # make pylint happy |
123 foreid = trinfo = None # make pylint happy |
124 |
124 |
125 def precommit_event(self): |
125 def precommit_event(self): |
126 cnx = self.cnx |
126 cnx = self.cnx |
127 forentity = self.forentity |
127 forentity = cnx.entity_from_eid(self.foreid) |
128 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
128 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
129 trinfo = self.trinfo |
129 trinfo = self.trinfo |
130 # we're in a subworkflow, check if we've reached an exit point |
130 # we're in a subworkflow, check if we've reached an exit point |
131 wftr = iworkflowable.subworkflow_input_transition() |
131 wftr = iworkflowable.subworkflow_input_transition() |
132 if wftr is None: |
132 if wftr is None: |
153 __regid__ = 'wfsetinitial' |
153 __regid__ = 'wfsetinitial' |
154 __select__ = WorkflowHook.__select__ & adaptable('IWorkflowable') |
154 __select__ = WorkflowHook.__select__ & adaptable('IWorkflowable') |
155 events = ('after_add_entity',) |
155 events = ('after_add_entity',) |
156 |
156 |
157 def __call__(self): |
157 def __call__(self): |
158 _SetInitialStateOp(self._cw, entity=self.entity) |
158 _SetInitialStateOp(self._cw, eid=self.entity.eid) |
159 |
159 |
160 |
160 |
161 class FireTransitionHook(WorkflowHook): |
161 class FireTransitionHook(WorkflowHook): |
162 """check the transition is allowed and add missing information into the |
162 """check the transition is allowed and add missing information into the |
163 TrInfo entity. |
163 TrInfo entity. |
253 entity.cw_edited['from_state'] = fromstate.eid |
253 entity.cw_edited['from_state'] = fromstate.eid |
254 entity.cw_edited['to_state'] = deststateeid |
254 entity.cw_edited['to_state'] = deststateeid |
255 nocheck = cnx.transaction_data.setdefault('skip-security', set()) |
255 nocheck = cnx.transaction_data.setdefault('skip-security', set()) |
256 nocheck.add((entity.eid, 'from_state', fromstate.eid)) |
256 nocheck.add((entity.eid, 'from_state', fromstate.eid)) |
257 nocheck.add((entity.eid, 'to_state', deststateeid)) |
257 nocheck.add((entity.eid, 'to_state', deststateeid)) |
258 _FireAutotransitionOp(cnx, entity=forentity) |
258 _FireAutotransitionOp(cnx, eid=forentity.eid) |
259 |
259 |
260 |
260 |
261 class FiredTransitionHook(WorkflowHook): |
261 class FiredTransitionHook(WorkflowHook): |
262 """change related entity state and handle exit of subworkflow""" |
262 """change related entity state and handle exit of subworkflow""" |
263 __regid__ = 'wffiretransition' |
263 __regid__ = 'wffiretransition' |
271 rcache['to_state']) |
271 rcache['to_state']) |
272 forentity = self._cw.entity_from_eid(rcache['wf_info_for']) |
272 forentity = self._cw.entity_from_eid(rcache['wf_info_for']) |
273 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
273 iworkflowable = forentity.cw_adapt_to('IWorkflowable') |
274 assert iworkflowable.current_state.eid == rcache['to_state'] |
274 assert iworkflowable.current_state.eid == rcache['to_state'] |
275 if iworkflowable.main_workflow.eid != iworkflowable.current_workflow.eid: |
275 if iworkflowable.main_workflow.eid != iworkflowable.current_workflow.eid: |
276 _SubWorkflowExitOp(self._cw, forentity=forentity, trinfo=trinfo) |
276 _SubWorkflowExitOp(self._cw, foreid=forentity.eid, trinfo=trinfo) |
277 |
277 |
278 |
278 |
279 class CheckInStateChangeAllowed(WorkflowHook): |
279 class CheckInStateChangeAllowed(WorkflowHook): |
280 """check state apply, in case of direct in_state change using unsafe execute |
280 """check state apply, in case of direct in_state change using unsafe execute |
281 """ |
281 """ |