Commit 3b5e770b authored by wenjie.zheng's avatar wenjie.zheng Committed by Sebastien Robin

Workflow.py: fix that transition can have single script defined; add a missing...

Workflow.py: fix that transition can have single script defined; add a missing function wrapWorkflowMethod.
parent ea9642a2
...@@ -211,9 +211,8 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): ...@@ -211,9 +211,8 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
def _findAutomaticTransition(self, document, sdef): def _findAutomaticTransition(self, document, sdef):
tdef = None tdef = None
for tid in sdef.getDestinationIdList(): for t in sdef.getDestinationValueList():
t = self._getOb(id=tid) if t.trigger_type == TRIGGER_AUTOMATIC:
if t is not None and t.trigger_type == TRIGGER_AUTOMATIC:
if self._checkTransitionGuard(t, document): if self._checkTransitionGuard(t, document):
tdef = t tdef = t
break break
...@@ -599,6 +598,8 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): ...@@ -599,6 +598,8 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
new_sdef = self.getSourceValue() new_sdef = self.getSourceValue()
new_state = new_sdef.getReference() new_state = new_sdef.getReference()
if not new_sdef: if not new_sdef:
# Do nothing if there is no initial state. We may want to create
# workflows with no state at all, only for worklists.
return return
former_status = {} former_status = {}
else: else:
...@@ -611,26 +612,26 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): ...@@ -611,26 +612,26 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
# Execute the "before" script. # Execute the "before" script.
before_script_success = 1 before_script_success = 1
if tdef is not None and tdef.getBeforeScriptId(): if tdef is not None and tdef.getBeforeScriptIdList():
script_id = tdef.getBeforeScriptId() script_id_list = tdef.getBeforeScriptIdList()
script = self._getOb(script_id, None) kwargs = form_kw
if script: sci = StateChangeInfo(
# Pass lots of info to the script in a single parameter. document, self, former_status, tdef, old_sdef, new_sdef, kwargs)
if script.getTypeInfo().getId() == 'Workflow Script': for script_id in script_id_list:
kwargs = form_kw script = self._getOb(script_id, None)
sci = StateChangeInfo( if script:
document, self, former_status, tdef, old_sdef, new_sdef, kwargs) # Pass lots of info to the script in a single parameter.
else: if script.getPortalType() != 'Workflow Script':
raise NotImplementedError ('Unsupported Script %s for state %s'%(script_id, old_sdef.getReference())) raise NotImplementedError ('Unsupported Script %s for state %s'%(script_id, old_sdef.getReference()))
try: try:
script(sci) # May throw an exception. script(sci) # May throw an exception.
except ValidationFailed, validation_exc: except ValidationFailed, validation_exc:
before_script_success = 0 before_script_success = 0
before_script_error_message = deepcopy(validation_exc.msg) before_script_error_message = deepcopy(validation_exc.msg)
validation_exc_traceback = sys.exc_traceback validation_exc_traceback = sys.exc_traceback
except ObjectMoved, moved_exc: except ObjectMoved, moved_exc:
ob = moved_exc.getNewObject() ob = moved_exc.getNewObject()
# Re-raise after transition # Re-raise after transition
# update variables # update variables
state_values = None state_values = None
...@@ -706,23 +707,24 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): ...@@ -706,23 +707,24 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
self.updateRoleMappingsFor(document) self.updateRoleMappingsFor(document)
# Execute the "after" script. # Execute the "after" script.
if tdef is not None: if tdef is not None and tdef.getAfterScriptIdList():
script_id = getattr(tdef, 'getAfterScriptId')() script_id_list = tdef.getAfterScriptIdList()
script = self._getOb(script_id, None) kwargs = form_kw
if script: sci = StateChangeInfo(
kwargs = form_kw
# Script can be either script or workflow method
if script_id in old_sdef.getDestinationIdList() and \
self._getOb(script_id).trigger_type == TRIGGER_WORKFLOW_METHOD:
getattr(document, convertToMixedCase(self._getOb(script_id).getReference()))()
else:
# Pass lots of info to the script in a single parameter.
if script.getTypeInfo().getId() == 'Workflow Script':
sci = StateChangeInfo(
document, self, former_status, tdef, old_sdef, new_sdef, kwargs) document, self, former_status, tdef, old_sdef, new_sdef, kwargs)
script(sci) # May throw an exception. for script_id in script_id_list:
script = self._getOb(script_id, None)
if script:
# Script can be either script or workflow method
if script_id in old_sdef.getDestinationIdList() and \
self._getOb(script_id).trigger_type == TRIGGER_WORKFLOW_METHOD:
getattr(document, convertToMixedCase(self._getOb(script_id).getReference()))()
else: else:
raise NotImplementedError ('Unsupported Script %s for state %s'%(script_id, old_sdef.getReference())) # Pass lots of info to the script in a single parameter.
if script.getPortalType() == 'Workflow Script':
script(sci) # May throw an exception.
else:
raise NotImplementedError ('Unsupported Script %s for state %s'%(script_id, old_sdef.getReference()))
# Return the new state object. # Return the new state object.
if moved_exc is not None: if moved_exc is not None:
# Propagate the notification that the object has moved. # Propagate the notification that the object has moved.
...@@ -730,6 +732,34 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): ...@@ -730,6 +732,34 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
else: else:
return new_sdef return new_sdef
def wrapWorkflowMethod(self, ob, method_id, func, args, kw):
'''
Allows the user to request a workflow action. This method
must perform its own security checks.
'''
sdef = self._getWorkflowStateOf(ob)
if sdef is None:
raise WorkflowException, 'Object is in an undefined state'
if method_id not in sdef.getTransitionIdList():
raise Unauthorized(method_id)
tdef = self.getTransitionValueList().get(method_id, None)
if tdef is None or tdef.trigger_type != TRIGGER_WORKFLOW_METHOD:
raise WorkflowException, (
'Transition %s is not triggered by a workflow method'
% method_id)
if not self._checkTransitionGuard(tdef, ob):
raise Unauthorized(method_id)
res = func(*args, **kw)
try:
self._changeStateOf(ob, tdef, kw)
except ObjectDeleted:
# Re-raise with a different result.
raise ObjectDeleted(res)
except ObjectMoved, ex:
# Re-raise with a different result.
raise ObjectMoved(ex.getNewObject(), res)
return res
def addTransition(self, name): def addTransition(self, name):
self.newContent(portal_type='Transition') self.newContent(portal_type='Transition')
self.setReference('dummy_workflow_method') self.setReference('dummy_workflow_method')
...@@ -1084,18 +1114,19 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject): ...@@ -1084,18 +1114,19 @@ class Workflow(IdAsReferenceMixin("", "prefix"), XMLObject):
# Always provide the state variable. # Always provide the state variable.
state_var = self.getStateVariable() state_var = self.getStateVariable()
status = self.getCurrentStatusDict(ob) status = self.getCurrentStatusDict(ob)
for id, vdef in self.getVariableValueList().iteritems(): for vdef_ref, vdef in self.getVariableValueList().iteritems():
if vdef.for_catalog: if vdef.for_catalog:
if status.has_key(id): if status.has_key(vdef_ref):
value = status[id] value = status[vdef_ref]
# Not set yet. Use a default. # Not set yet. Use a default.
elif vdef.default_expr is not None: elif vdef.default_expr is not None:
ec = createExprContext(StateChangeInfo(ob, self, status)) ec = createExprContext(StateChangeInfo(ob, self, status))
value = vdef.default_expr(ec) # convert string to expression before execute it.
value = Expression(vdef.default_expr)(ec)
else: else:
value = vdef.default_value value = vdef.default_value
res[id] = value res[vdef_ref] = value
if hasattr(self, 'getSourceValue'): if hasattr(self, 'getSourceValue'):
if self.getSourceValue() is not None: if self.getSourceValue() is not None:
initial_state = self.getSourceValue().getReference() initial_state = self.getSourceValue().getReference()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment