diff -r d3cd8bd20ee5 -r a2aa2c51f3be server/hooks.py --- a/server/hooks.py Fri Aug 21 08:45:16 2009 +0200 +++ b/server/hooks.py Fri Aug 21 08:45:55 2009 +0200 @@ -418,6 +418,15 @@ # workflow handling ########################################################### +def _change_state(session, x, oldstate, newstate): + nocheck = session.transaction_data.setdefault('skip-security', set()) + nocheck.add((x, 'in_state', oldstate)) + nocheck.add((x, 'in_state', newstate)) + # delete previous state first in case we're using a super session + session.delete_relation(x, 'in_state', oldstate) + session.add_relation(x, 'in_state', newstate) + + def before_add_trinfo(session, entity): """check the transition is allowed, add missing information. Expect that: * wf_info_for inlined relation is set @@ -477,16 +486,11 @@ nocheck.add((entity.eid, 'from_state', fromstate.eid)) nocheck.add((entity.eid, 'to_state', deststateeid)) + def after_add_trinfo(session, entity): """change related entity state""" - # need to delete previous state first, not done automatically since - # we're using a super session - session.unsafe_execute('DELETE X in_state S WHERE X eid %(x)s, S eid %(s)s', - {'x': entity['wf_info_for'], 's': entity['from_state']}, - ('x', 's')) - session.unsafe_execute('SET X in_state S WHERE X eid %(x)s, S eid %(s)s', - {'x': entity['wf_info_for'], 's': entity['to_state']}, - ('x', 's')) + _change_state(session, entity['wf_info_for'], + entity['from_state'], entity['to_state']) class SetInitialStateOp(PreCommitOperation): @@ -510,6 +514,48 @@ def set_initial_state_after_add(session, entity): SetInitialStateOp(session, entity=entity) + +class WorkflowChangedOp(PreCommitOperation): + """fix entity current state when changing its workflow""" + + def precommit_event(self): + session = self.session + pendingeids = session.transaction_data.get('pendingeids', ()) + if self.eid in pendingeids: + return + entity = session.entity_from_eid(self.eid) + # notice that enforcment that new workflow apply to the entity's type is + # done by schema rule, no need to check it here + if entity.current_workflow.eid == self.wfeid: + deststate = entity.current_workflow.initial + if not deststate: + msg = session._('workflow has no initial state') + raise ValidationError(entity.eid, {'custom_workflow': msg}) + if entity.current_workflow.state_by_eid(entity.current_state.eid): + # nothing to do + return + # if there are no history, simply go to new workflow's initial state + if not entity.workflow_history: + if entity.current_state.eid != deststate.eid: + _change_state(session, entity.eid, + entity.current_state.eid, deststate.eid) + return + msg = session._('workflow changed to "%s"') + msg %= entity.current_workflow.name + entity.change_state(deststate.name, msg) + + +def set_custom_workflow(session, eidfrom, rtype, eidto): + WorkflowChangedOp(session, eid=eidfrom, wfeid=eidto) + + +def del_custom_workflow(session, eidfrom, rtype, eidto): + entity = session.entity_from_eid(eidfrom) + typewf = entity.cwetype_workflow() + if typewf is not None: + WorkflowChangedOp(session, eid=eidfrom, wfeid=typewf.eid) + + def after_del_workflow(session, eid): # workflow cleanup session.execute('DELETE State X WHERE NOT X state_of Y') @@ -526,6 +572,8 @@ if 'in_state' in eschema.subject_relations(): hm.register_hook(set_initial_state_after_add, 'after_add_entity', str(eschema)) + hm.register_hook(set_custom_workflow, 'after_add_relation', 'custom_workflow') + hm.register_hook(del_custom_workflow, 'after_delete_relation', 'custom_workflow') hm.register_hook(after_del_workflow, 'after_delete_entity', 'Workflow')