introduce 'go back' transition: transition without destination state will go to the state we were coming from stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 19 Feb 2010 09:36:26 +0100
branchstable
changeset 4644 021035b9a7ab
parent 4643 921737d2e3a8
child 4645 fd4e32f17211
introduce 'go back' transition: transition without destination state will go to the state we were coming from
entities/test/unittest_wfobjs.py
entities/wfobjs.py
hooks/workflow.py
misc/migration/3.6.1_Any.py
schemas/workflow.py
--- a/entities/test/unittest_wfobjs.py	Fri Feb 19 09:34:14 2010 +0100
+++ b/entities/test/unittest_wfobjs.py	Fri Feb 19 09:36:26 2010 +0100
@@ -98,7 +98,7 @@
         trs = list(user.possible_transitions())
         self.assertEquals(len(trs), 1)
         self.assertEquals(trs[0].name, u'deactivate')
-        self.assertEquals(trs[0].destination().name, u'deactivated')
+        self.assertEquals(trs[0].destination(None).name, u'deactivated')
         # test a std user get no possible transition
         cnx = self.login('member')
         # fetch the entity using the new session
@@ -141,6 +141,27 @@
         trinfo = self._test_manager_deactivate(user)
         self.assertEquals(trinfo.transition.name, 'deactivate')
 
+    def test_goback_transition(self):
+        wf = self.session.user.current_workflow
+        asleep = wf.add_state('asleep')
+        wf.add_transition('rest', (wf.state_by_name('activated'), wf.state_by_name('deactivated')),
+                               asleep)
+        wf.add_transition('wake up', asleep)
+        user = self.create_user('stduser')
+        user.fire_transition('rest')
+        self.commit()
+        user.fire_transition('wake up')
+        self.commit()
+        self.assertEquals(user.state, 'activated')
+        user.fire_transition('deactivate')
+        self.commit()
+        user.fire_transition('rest')
+        self.commit()
+        user.fire_transition('wake up')
+        self.commit()
+        user.clear_all_caches()
+        self.assertEquals(user.state, 'deactivated')
+
     # XXX test managers can change state without matching transition
 
     def _test_stduser_deactivate(self):
@@ -207,7 +228,7 @@
         state3 = mwf.add_state(u'state3')
         swftr1 = mwf.add_wftransition(u'swftr1', swf, state1,
                                       [(swfstate2, state2), (swfstate3, state3)])
-        self.assertEquals(swftr1.destination().eid, swfstate1.eid)
+        self.assertEquals(swftr1.destination(None).eid, swfstate1.eid)
         # workflows built, begin test
         self.group = self.request().create_entity('CWGroup', name=u'grp1')
         self.commit()
--- a/entities/wfobjs.py	Fri Feb 19 09:34:14 2010 +0100
+++ b/entities/wfobjs.py	Fri Feb 19 09:36:26 2010 +0100
@@ -256,8 +256,12 @@
     """customized class for Transition entities"""
     __regid__ = 'Transition'
 
-    def destination(self):
-        return self.destination_state[0]
+    def destination(self, entity):
+        try:
+            return self.destination_state[0]
+        except IndexError:
+            return entity.latest_trinfo().previous_state
+
 
     def parent(self):
         return self.workflow
--- a/hooks/workflow.py	Fri Feb 19 09:34:14 2010 +0100
+++ b/hooks/workflow.py	Fri Feb 19 09:36:26 2010 +0100
@@ -232,7 +232,7 @@
                     raise ValidationError(entity.eid, {'by_transition': msg})
             if entity.get('to_state'):
                 deststateeid = entity['to_state']
-                if not cowpowers and deststateeid != tr.destination().eid:
+                if not cowpowers and deststateeid != tr.destination(forentity).eid:
                     msg = session._("transition isn't allowed")
                     raise ValidationError(entity.eid, {'by_transition': msg})
                 if swtr is None:
@@ -241,7 +241,7 @@
                         msg = session._("state doesn't belong to entity's workflow")
                         raise ValidationError(entity.eid, {'to_state': msg})
             else:
-                deststateeid = tr.destination().eid
+                deststateeid = tr.destination(forentity).eid
         # everything is ok, add missing information on the trinfo entity
         entity['from_state'] = fromstate.eid
         entity['to_state'] = deststateeid
--- a/misc/migration/3.6.1_Any.py	Fri Feb 19 09:34:14 2010 +0100
+++ b/misc/migration/3.6.1_Any.py	Fri Feb 19 09:36:26 2010 +0100
@@ -1,1 +1,2 @@
 sync_schema_props_perms(syncprops=False)
+sync_schema_props_perms('destination_state', syncperms=False)
--- a/schemas/workflow.py	Fri Feb 19 09:34:14 2010 +0100
+++ b/schemas/workflow.py	Fri Feb 19 09:36:26 2010 +0100
@@ -97,12 +97,13 @@
 
 class Transition(BaseTransition):
     """use to define a transition from one or multiple states to a destination
-    states in workflow's definitions.
+    states in workflow's definitions. Transition without destination state will
+    go back to the state from which we arrived to the current state.
     """
     __specializes_schema__ = True
 
     destination_state = SubjectRelation(
-        'State', cardinality='1*',
+        'State', cardinality='?*',
         constraints=[RQLConstraint('S transition_of WF, O state_of WF',
                                    msg=_('state and transition don\'t belong the the same workflow'))],
         description=_('destination state for this transition'))