From 2160a8045db55ab74bffba77153d5980d1f8157c Mon Sep 17 00:00:00 2001 From: Jean-Paul Smets <jp@nexedi.com> Date: Thu, 1 Mar 2007 22:45:53 +0000 Subject: [PATCH] Pass method variables to workflow history. This change may be good or not. I do not know yet. Reviewing this code and patches is required. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@13171 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5Type/patches/DCWorkflow.py | 44 +++++++++++++++++++----- product/ERP5Type/patches/WorkflowTool.py | 30 ++++++++++------ 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/product/ERP5Type/patches/DCWorkflow.py b/product/ERP5Type/patches/DCWorkflow.py index 92248918e2..450223389c 100644 --- a/product/ERP5Type/patches/DCWorkflow.py +++ b/product/ERP5Type/patches/DCWorkflow.py @@ -16,7 +16,8 @@ from Globals import DTMLFile from Products.ERP5Type import _dtmldir -from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition, StateChangeInfo, ObjectMoved, createExprContext, aq_parent, aq_inner +from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition, StateChangeInfo, createExprContext +from Products.DCWorkflow.DCWorkflow import ObjectDeleted, ObjectMoved, aq_parent, aq_inner from Products.DCWorkflow import DCWorkflow from Products.DCWorkflow.Transitions import TRIGGER_WORKFLOW_METHOD, TransitionDefinition from AccessControl import getSecurityManager, ClassSecurityInfo, ModuleSecurityInfo @@ -30,8 +31,6 @@ from Products.ERP5Type.Utils import convertToMixedCase from string import join from zLOG import LOG - - # Patch WorkflowUIMixin to add description on workflows from Products.DCWorkflow.WorkflowUIMixin import WorkflowUIMixin as WorkflowUIMixin_class from Products.DCWorkflow.Guard import Guard @@ -57,7 +56,6 @@ WorkflowUIMixin_class.setProperties = WorkflowUIMixin_setProperties WorkflowUIMixin_class.manage_properties = DTMLFile('workflow_properties', _dtmldir) - def DCWorkflowDefinition_listGlobalActions(self, info): ''' Allows this workflow to @@ -144,7 +142,6 @@ DCWorkflow.ValidationFailed = ValidationFailed ModuleSecurityInfo('Products.DCWorkflow.DCWorkflow').declarePublic('ValidationFailed') - # Patch excecuteTransition from DCWorkflowDefinition, to put ValidationFailed # error messages in workflow history. def DCWorkflowDefinition_executeTransition(self, ob, tdef=None, kwargs=None): @@ -271,10 +268,41 @@ def DCWorkflowDefinition_executeTransition(self, ob, tdef=None, kwargs=None): else: return new_sdef - DCWorkflowDefinition._executeTransition = DCWorkflowDefinition_executeTransition from Products.DCWorkflow.utils import modifyRolesForPermission + +def DCWorkflowDefinition_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.transitions: + raise Unauthorized(method_id) + tdef = self.transitions.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 + +DCWorkflowDefinition.wrapWorkflowMethod = DCWorkflowDefinition_wrapWorkflowMethod + + # Patch updateRoleMappingsFor so that if 2 workflows define security, then we # should do an AND operation between each permission def updateRoleMappingsFor(self, ob): @@ -453,6 +481,4 @@ def createERP5Workflow(id): addWorkflowFactory(createERP5Workflow, id='erp5_workflow', - title='ERP5-style empty workflow') - - + title='ERP5-style empty workflow') \ No newline at end of file diff --git a/product/ERP5Type/patches/WorkflowTool.py b/product/ERP5Type/patches/WorkflowTool.py index 6838ca6063..f20c0eb7d2 100644 --- a/product/ERP5Type/patches/WorkflowTool.py +++ b/product/ERP5Type/patches/WorkflowTool.py @@ -12,6 +12,8 @@ # ############################################################################## +from zLOG import LOG + # Make sure Interaction Workflows are called even if method not wrapped from Products.CMFCore.WorkflowTool import WorkflowTool @@ -25,24 +27,25 @@ def WorkflowTool_wrapWorkflowMethod(self, ob, method_id, func, args, kw): By default, the workflow tool takes the first workflow wich support the method_id. In ERP5, with Interaction Worfklows, we may have many workflows wich can support a worfklow method, - that's why we need this patch + that's why we need this patch. + + Current implementation supports: + - at most 1 DCWorkflow per portal type per method_id + - as many Interaction workflows as needed per portal type + + NOTE: automatic transitions are invoked through + _findAutomaticTransition in DC Workflows. - We should have 1 or 0 classic workflow (ie a DCWorkflow), and - 0 or many Interaction workflows. We should take care that the - method will be called once + TODO: make it possible to have multiple DC Workflow + per portal type per method_id """ # Check workflow containing the workflow method wf_list = [] wfs = self.getWorkflowsFor(ob) if wfs: for w in wfs: -# LOG('ERP5WorkflowTool.wrapWorkflowMethod, is wfMSupported', 0, -# repr((w.isWorkflowMethodSupported(ob, method_id), -# w.getId(), ob, method_id ))) if (hasattr(w, 'isWorkflowMethodSupported') - and w.isWorkflowMethodSupported(ob, method_id)): - #wf = w - #break + and w.isWorkflowMethodSupported(ob, method_id)): wf_list.append(w) else: wfs = () @@ -58,6 +61,13 @@ def WorkflowTool_wrapWorkflowMethod(self, ob, method_id, func, args, kw): for w in wf_list: if w.__class__.__name__ != 'InteractionWorkflowDefinition': only_interaction_defined = 0 + # XXX - There is a problem here if the same workflow method + # is used by multiple workflows. Function "func" will be + # called multiple times. Patch or changes required to mak + # sure func is only called once. + # Solution consists in reimplementing _invokeWithNotification + # at the level of each workflow without notification + # (ex. _invokeWithoutNotification) result = self._invokeWithNotification( [], ob, method_id, w.wrapWorkflowMethod, (ob, method_id, func, args, kw), {}) -- 2.30.9