cubicweb/hooks/workflow.py
changeset 11242 b05c7a96d621
parent 11057 0b59724cb3f2
child 11767 432f87a63057
equal deleted inserted replaced
11241:a2091fa8cb2c 11242:b05c7a96d621
    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     """