hooks/workflow.py
author Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
Mon, 08 Mar 2010 19:11:47 +0100
changeset 4830 10e8bc190695
parent 4719 aaed3f813ef8
child 4835 13b0b96d7982
permissions -rw-r--r--
[javascript] fix #736185: add_onload / jQuery.bind() vs. jQuery.one() This patch introduces a new 'server-response' event and deprecates the 'ajax-loaded' event. - 'server-response' is triggered by postAjaxLoad() (instead of 'ajax-loaded'). - 'server-response' is also triggered on document.ready(). - The add_onload() method binds the javascript code the 'server-response' event whether or not it's an ajax request, thus removing the need of the jsoncall hackish parameter. The binding is done with jQuery.one() instead of jQuery.bind(). - The javascript callbacks will be passed two extra parameters : a boolean to indicate if it's an ajax request or not, the DOM node (result of the HTTP query). As javascript is what it is, callbacks can safely ignore those two parameters if they don't need them. Backward compatibility is maintained by triggerring an 'ajax-loaded' event when a 'server-response' is emitted.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     1
"""Core hooks: workflow related hooks
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     2
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     3
:organization: Logilab
4307
7fba9c34c88f update copyright
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4181
diff changeset
     4
:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     5
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     6
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     7
"""
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     8
__docformat__ = "restructuredtext en"
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
     9
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    10
from datetime import datetime
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    11
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    12
from cubicweb import RepositoryError, ValidationError
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    13
from cubicweb.interfaces import IWorkflowable
4075
e710f4052bd6 use implements instead of entity_implements
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4024
diff changeset
    14
from cubicweb.selectors import implements
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    15
from cubicweb.server import hook
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    16
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    17
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    18
def _change_state(session, x, oldstate, newstate):
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    19
    nocheck = session.transaction_data.setdefault('skip-security', set())
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    20
    nocheck.add((x, 'in_state', oldstate))
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    21
    nocheck.add((x, 'in_state', newstate))
3072
6fb42c53f6df backport 3.5 branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3024
diff changeset
    22
    # delete previous state first in case we're using a super session,
6fb42c53f6df backport 3.5 branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3024
diff changeset
    23
    # unless in_state isn't stored in the system source
6fb42c53f6df backport 3.5 branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3024
diff changeset
    24
    fromsource = session.describe(x)[1]
6fb42c53f6df backport 3.5 branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3024
diff changeset
    25
    if fromsource == 'system' or \
6fb42c53f6df backport 3.5 branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3024
diff changeset
    26
           not session.repo.sources_by_uri[fromsource].support_relation('in_state'):
6fb42c53f6df backport 3.5 branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3024
diff changeset
    27
        session.delete_relation(x, 'in_state', oldstate)
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    28
    session.add_relation(x, 'in_state', newstate)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    29
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    30
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    31
# operations ###################################################################
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    32
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
    33
class _SetInitialStateOp(hook.Operation):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    34
    """make initial state be a default state"""
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    35
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    36
    def precommit_event(self):
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    37
        session = self.session
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    38
        entity = self.entity
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    39
        # if there is an initial state and the entity's state is not set,
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
    40
        # use the initial state as a default state
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    41
        if not (session.deleted_in_transaction(entity.eid) or entity.in_state) \
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    42
               and entity.current_workflow:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    43
            state = entity.current_workflow.initial
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    44
            if state:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    45
                # use super session to by-pass security checks
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    46
                session.super_session.add_relation(entity.eid, 'in_state',
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    47
                                                   state.eid)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    48
3536
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    49
3589
a5432f99f2d9 backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3536
diff changeset
    50
class _FireAutotransitionOp(hook.Operation):
3536
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    51
    """try to fire auto transition after state changes"""
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    52
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    53
    def precommit_event(self):
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    54
        entity = self.entity
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    55
        autotrs = list(entity.possible_transitions('auto'))
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    56
        if autotrs:
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    57
            assert len(autotrs) == 1
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    58
            entity.fire_transition(autotrs[0])
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    59
f6c9a5df80fb backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3449
diff changeset
    60
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    61
class _WorkflowChangedOp(hook.Operation):
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    62
    """fix entity current state when changing its workflow"""
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    63
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    64
    def precommit_event(self):
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    65
        # notice that enforcement that new workflow apply to the entity's type is
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    66
        # done by schema rule, no need to check it here
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    67
        session = self.session
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    68
        pendingeids = session.transaction_data.get('pendingeids', ())
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    69
        if self.eid in pendingeids:
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    70
            return
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    71
        entity = session.entity_from_eid(self.eid)
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    72
        # check custom workflow has not been rechanged to another one in the same
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    73
        # transaction
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    74
        mainwf = entity.main_workflow
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    75
        if mainwf.eid == self.wfeid:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    76
            deststate = mainwf.initial
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    77
            if not deststate:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    78
                msg = session._('workflow has no initial state')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    79
                raise ValidationError(entity.eid, {'custom_workflow': msg})
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    80
            if mainwf.state_by_eid(entity.current_state.eid):
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    81
                # nothing to do
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    82
                return
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    83
            # if there are no history, simply go to new workflow's initial state
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    84
            if not entity.workflow_history:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    85
                if entity.current_state.eid != deststate.eid:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    86
                    _change_state(session, entity.eid,
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    87
                                  entity.current_state.eid, deststate.eid)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    88
                return
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    89
            msg = session._('workflow changed to "%s"')
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    90
            msg %= session._(mainwf.name)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    91
            session.transaction_data[(entity.eid, 'customwf')] = self.wfeid
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    92
            entity.change_state(deststate, msg, u'text/plain')
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    93
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
    94
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    95
class _CheckTrExitPoint(hook.Operation):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    96
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    97
    def precommit_event(self):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    98
        tr = self.session.entity_from_eid(self.treid)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
    99
        outputs = set()
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   100
        for ep in tr.subworkflow_exit:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   101
            if ep.subwf_state.eid in outputs:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   102
                msg = self.session._("can't have multiple exits on the same state")
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   103
                raise ValidationError(self.treid, {'subworkflow_exit': msg})
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   104
            outputs.add(ep.subwf_state.eid)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   105
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   106
3675
5d143781a604 fix merge
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3674
diff changeset
   107
class _SubWorkflowExitOp(hook.Operation):
3674
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   108
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   109
    def precommit_event(self):
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   110
        session = self.session
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   111
        forentity = self.forentity
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   112
        trinfo = self.trinfo
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   113
        # we're in a subworkflow, check if we've reached an exit point
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   114
        wftr = forentity.subworkflow_input_transition()
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   115
        if wftr is None:
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   116
            # inconsistency detected
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   117
            msg = session._("state doesn't belong to entity's current workflow")
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   118
            raise ValidationError(self.trinfo.eid, {'to_state': msg})
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   119
        tostate = wftr.get_exit_point(forentity, trinfo['to_state'])
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   120
        if tostate is not None:
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   121
            # reached an exit point
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   122
            msg = session._('exiting from subworkflow %s')
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   123
            msg %= session._(forentity.current_workflow.name)
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   124
            session.transaction_data[(forentity.eid, 'subwfentrytr')] = True
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   125
            # XXX iirk
4024
6a14cff373c3 more api update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4003
diff changeset
   126
            req = forentity._cw
6a14cff373c3 more api update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4003
diff changeset
   127
            forentity._cw = session.super_session
3674
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   128
            try:
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   129
                trinfo = forentity.change_state(tostate, msg, u'text/plain',
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   130
                                                tr=wftr)
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   131
            finally:
4024
6a14cff373c3 more api update
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4003
diff changeset
   132
                forentity._cw = req
3674
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   133
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   134
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   135
# hooks ########################################################################
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   136
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   137
class WorkflowHook(hook.Hook):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   138
    __abstract__ = True
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   139
    category = 'worfklow'
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   140
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   141
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   142
class SetInitialStateHook(WorkflowHook):
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   143
    __regid__ = 'wfsetinitial'
4075
e710f4052bd6 use implements instead of entity_implements
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4024
diff changeset
   144
    __select__ = WorkflowHook.__select__ & implements(IWorkflowable)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   145
    events = ('after_add_entity',)
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   146
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   147
    def __call__(self):
2847
c2ee28f4d4b1 use ._cw instead of .cw_req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2841
diff changeset
   148
        _SetInitialStateOp(self._cw, entity=self.entity)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   149
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   150
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   151
class PrepareStateChangeHook(WorkflowHook):
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   152
    """record previous state information"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   153
    __regid__ = 'cwdelstate'
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   154
    __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state')
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   155
    events = ('before_delete_relation',)
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   156
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   157
    def __call__(self):
2847
c2ee28f4d4b1 use ._cw instead of .cw_req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2841
diff changeset
   158
        self._cw.transaction_data.setdefault('pendingrelations', []).append(
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   159
            (self.eidfrom, self.rtype, self.eidto))
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   160
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   161
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   162
class FireTransitionHook(WorkflowHook):
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   163
    """check the transition is allowed, add missing information. Expect that:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   164
    * wf_info_for inlined relation is set
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   165
    * by_transition or to_state (managers only) inlined relation is set
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   166
    """
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   167
    __regid__ = 'wffiretransition'
4075
e710f4052bd6 use implements instead of entity_implements
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4024
diff changeset
   168
    __select__ = WorkflowHook.__select__ & implements('TrInfo')
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   169
    events = ('before_add_entity',)
2835
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   170
04034421b072 [hooks] major refactoring:
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents:
diff changeset
   171
    def __call__(self):
2847
c2ee28f4d4b1 use ._cw instead of .cw_req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2841
diff changeset
   172
        session = self._cw
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   173
        entity = self.entity
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   174
        # first retreive entity to which the state change apply
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   175
        try:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   176
            foreid = entity['wf_info_for']
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   177
        except KeyError:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   178
            msg = session._('mandatory relation')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   179
            raise ValidationError(entity.eid, {'wf_info_for': msg})
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   180
        forentity = session.entity_from_eid(foreid)
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   181
        # then check it has a workflow set, unless we're in the process of changing
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   182
        # entity's workflow
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   183
        if session.transaction_data.get((forentity.eid, 'customwf')):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   184
            wfeid = session.transaction_data[(forentity.eid, 'customwf')]
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   185
            wf = session.entity_from_eid(wfeid)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   186
        else:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   187
            wf = forentity.current_workflow
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   188
        if wf is None:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   189
            msg = session._('related entity has no workflow set')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   190
            raise ValidationError(entity.eid, {None: msg})
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   191
        # then check it has a state set
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   192
        fromstate = forentity.current_state
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   193
        if fromstate is None:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   194
            msg = session._('related entity has no state')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   195
            raise ValidationError(entity.eid, {None: msg})
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   196
        # True if we are coming back from subworkflow
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   197
        swtr = session.transaction_data.pop((forentity.eid, 'subwfentrytr'), None)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   198
        cowpowers = session.is_super_session or 'managers' in session.user.groups
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   199
        # no investigate the requested state change...
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   200
        try:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   201
            treid = entity['by_transition']
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   202
        except KeyError:
3894
27cbf98ad863 forgotten stuff
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3890
diff changeset
   203
            # no transition set, check user is a manager and destination state
27cbf98ad863 forgotten stuff
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3890
diff changeset
   204
            # is specified (and valid)
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   205
            if not cowpowers:
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   206
                msg = session._('mandatory relation')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   207
                raise ValidationError(entity.eid, {'by_transition': msg})
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   208
            deststateeid = entity.get('to_state')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   209
            if not deststateeid:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   210
                msg = session._('mandatory relation')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   211
                raise ValidationError(entity.eid, {'by_transition': msg})
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   212
            deststate = wf.state_by_eid(deststateeid)
3777
3ef8cdb5fb1c backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3739
diff changeset
   213
            if deststate is None:
3449
063488f14a0f no need to access to _ through entity.req...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3376
diff changeset
   214
                msg = session._("state doesn't belong to entity's workflow")
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   215
                raise ValidationError(entity.eid, {'to_state': msg})
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   216
        else:
3894
27cbf98ad863 forgotten stuff
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3890
diff changeset
   217
            # check transition is valid and allowed, unless we're coming back
27cbf98ad863 forgotten stuff
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3890
diff changeset
   218
            # from subworkflow
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   219
            tr = session.entity_from_eid(treid)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   220
            if swtr is None:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   221
                if tr is None:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   222
                    msg = session._("transition doesn't belong to entity's workflow")
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   223
                    raise ValidationError(entity.eid, {'by_transition': msg})
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   224
                if not tr.has_input_state(fromstate):
4181
c79135c217df backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4088
diff changeset
   225
                    msg = session._("transition %(tr)s isn't allowed from %(st)s") % {
c79135c217df backport stable
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4088
diff changeset
   226
                        'tr': session._(tr.name), 'st': session._(fromstate.name)}
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   227
                    raise ValidationError(entity.eid, {'by_transition': msg})
4003
b9436fe77c9e fix bad merge
Sandrine Ribeau <sandrine.ribeau@logilab.fr>
parents: 3894
diff changeset
   228
                if not tr.may_be_fired(foreid):
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   229
                    msg = session._("transition may not be fired")
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   230
                    raise ValidationError(entity.eid, {'by_transition': msg})
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   231
            if entity.get('to_state'):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   232
                deststateeid = entity['to_state']
4644
021035b9a7ab introduce 'go back' transition: transition without destination state will go to the state we were coming from
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
   233
                if not cowpowers and deststateeid != tr.destination(forentity).eid:
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   234
                    msg = session._("transition isn't allowed")
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   235
                    raise ValidationError(entity.eid, {'by_transition': msg})
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   236
                if swtr is None:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   237
                    deststate = session.entity_from_eid(deststateeid)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   238
                    if not cowpowers and deststate is None:
3449
063488f14a0f no need to access to _ through entity.req...
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3376
diff changeset
   239
                        msg = session._("state doesn't belong to entity's workflow")
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   240
                        raise ValidationError(entity.eid, {'to_state': msg})
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   241
            else:
4644
021035b9a7ab introduce 'go back' transition: transition without destination state will go to the state we were coming from
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4307
diff changeset
   242
                deststateeid = tr.destination(forentity).eid
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   243
        # everything is ok, add missing information on the trinfo entity
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   244
        entity['from_state'] = fromstate.eid
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   245
        entity['to_state'] = deststateeid
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   246
        nocheck = session.transaction_data.setdefault('skip-security', set())
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   247
        nocheck.add((entity.eid, 'from_state', fromstate.eid))
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   248
        nocheck.add((entity.eid, 'to_state', deststateeid))
3739
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3675
diff changeset
   249
        _FireAutotransitionOp(session, entity=forentity)
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   250
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   251
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   252
class FiredTransitionHook(WorkflowHook):
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   253
    """change related entity state"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   254
    __regid__ = 'wffiretransition'
4075
e710f4052bd6 use implements instead of entity_implements
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4024
diff changeset
   255
    __select__ = WorkflowHook.__select__ & implements('TrInfo')
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   256
    events = ('after_add_entity',)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   257
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   258
    def __call__(self):
3674
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   259
        trinfo = self.entity
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   260
        _change_state(self._cw, trinfo['wf_info_for'],
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   261
                      trinfo['from_state'], trinfo['to_state'])
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   262
        forentity = self._cw.entity_from_eid(trinfo['wf_info_for'])
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   263
        assert forentity.current_state.eid == trinfo['to_state']
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   264
        if forentity.main_workflow.eid != forentity.current_workflow.eid:
3674
387d51af966d backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3654
diff changeset
   265
            _SubWorkflowExitOp(self._cw, forentity=forentity, trinfo=trinfo)
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   266
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   267
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   268
class CheckInStateChangeAllowed(WorkflowHook):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   269
    """check state apply, in case of direct in_state change using unsafe_execute
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   270
    """
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   271
    __regid__ = 'wfcheckinstate'
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   272
    __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state')
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   273
    events = ('before_add_relation',)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   274
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   275
    def __call__(self):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   276
        session = self._cw
4088
23ce2b3fb03d don't use setdefault with a tuple as value, a set is expected
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 4075
diff changeset
   277
        nocheck = session.transaction_data.get('skip-security', ())
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   278
        if (self.eidfrom, 'in_state', self.eidto) in nocheck:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   279
            # state changed through TrInfo insertion, so we already know it's ok
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   280
            return
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   281
        entity = session.entity_from_eid(self.eidfrom)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   282
        mainwf = entity.main_workflow
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   283
        if mainwf is None:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   284
            msg = session._('entity has no workflow set')
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   285
            raise ValidationError(entity.eid, {None: msg})
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   286
        for wf in mainwf.iter_workflows():
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   287
            if wf.state_by_eid(self.eidto):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   288
                break
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   289
        else:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   290
            msg = session._("state doesn't belong to entity's workflow. You may "
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   291
                            "want to set a custom workflow for this entity first.")
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   292
            raise ValidationError(self.eidfrom, {'in_state': msg})
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   293
        if entity.current_workflow and wf.eid != entity.current_workflow.eid:
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   294
            msg = session._("state doesn't belong to entity's current workflow")
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   295
            raise ValidationError(self.eidfrom, {'in_state': msg})
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   296
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   297
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   298
class SetModificationDateOnStateChange(WorkflowHook):
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   299
    """update entity's modification date after changing its state"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   300
    __regid__ = 'wfsyncmdate'
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   301
    __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state')
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   302
    events = ('after_add_relation',)
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   303
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   304
    def __call__(self):
2847
c2ee28f4d4b1 use ._cw instead of .cw_req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2841
diff changeset
   305
        if self._cw.added_in_transaction(self.eidfrom):
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   306
            # new entity, not needed
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   307
            return
2847
c2ee28f4d4b1 use ._cw instead of .cw_req
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2841
diff changeset
   308
        entity = self._cw.entity_from_eid(self.eidfrom)
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   309
        try:
2880
bfc8e1831290 backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2847
diff changeset
   310
            entity.set_attributes(modification_date=datetime.now(),
bfc8e1831290 backport stable branch
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2847
diff changeset
   311
                                  _cw_unsafe=True)
2841
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   312
        except RepositoryError, ex:
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   313
            # usually occurs if entity is coming from a read-only source
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   314
            # (eg ldap user)
107ba1c45227 rewrite hooks in sobjects as new Hook style into hooks sub-package
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2835
diff changeset
   315
            self.warning('cant change modification date for %s: %s', entity, ex)
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   316
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   317
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   318
class CheckWorkflowTransitionExitPoint(WorkflowHook):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   319
    """check that there is no multiple exits from the same state"""
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   320
    __regid__ = 'wfcheckwftrexit'
3024
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   321
    __select__ = WorkflowHook.__select__ & hook.match_rtype('subworkflow_exit')
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   322
    events = ('after_add_relation',)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   323
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   324
    def __call__(self):
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   325
        _CheckTrExitPoint(self._cw, treid=self.eidfrom)
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   326
bfaf056f1029 backport 3.5 step 2, backport wf changes in hooks/workflow.py
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2968
diff changeset
   327
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   328
class SetCustomWorkflow(WorkflowHook):
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   329
    __regid__ = 'wfsetcustom'
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   330
    __select__ = WorkflowHook.__select__ & hook.match_rtype('custom_workflow')
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   331
    events = ('after_add_relation',)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   332
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   333
    def __call__(self):
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   334
        _WorkflowChangedOp(self._cw, eid=self.eidfrom, wfeid=self.eidto)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   335
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   336
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   337
class DelCustomWorkflow(SetCustomWorkflow):
3376
f5c69485381f [appobjects] use __regid__ instead of __id__, more explicit
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 3072
diff changeset
   338
    __regid__ = 'wfdelcustom'
2968
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   339
    events = ('after_delete_relation',)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   340
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   341
    def __call__(self):
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   342
        entity = self._cw.entity_from_eid(self.eidfrom)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   343
        typewf = entity.cwetype_workflow()
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   344
        if typewf is not None:
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   345
            _WorkflowChangedOp(self._cw, eid=self.eidfrom, wfeid=typewf.eid)
0e3460341023 somewhat painful backport of 3.5 branch, should mostly be ok
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 2880
diff changeset
   346