Commit 3c54c622 authored by wenjie.zheng's avatar wenjie.zheng

Workflow.py: Add TRIGGER mechanism and ERP5 Workflow Action trigger doActionFor.

parent 37c3c7b6
...@@ -27,9 +27,12 @@ ...@@ -27,9 +27,12 @@
############################################################################## ##############################################################################
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.unauthorized import Unauthorized
from Acquisition import aq_inner from Acquisition import aq_inner
from Acquisition import aq_parent from Acquisition import aq_parent
from Products.DCWorkflow.utils import modifyRolesForPermission from Products.DCWorkflow.utils import modifyRolesForPermission
from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition as DCWorkflow
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Globals import PersistentMapping from Products.ERP5Type.Globals import PersistentMapping
...@@ -37,8 +40,16 @@ from Products.ERP5Type.Accessor import WorkflowState ...@@ -37,8 +40,16 @@ from Products.ERP5Type.Accessor import WorkflowState
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from tempfile import mktemp from tempfile import mktemp
import os import os
from Products.CMFCore.WorkflowCore import WorkflowException
from Products.ERP5Workflow.Document.Transition import TRIGGER_AUTOMATIC
from Products.ERP5Workflow.Document.Transition import TRIGGER_USER_ACTION
from Products.ERP5Workflow.Document.Transition import TRIGGER_WORKFLOW_METHOD
from Products.DCWorkflowGraph.config import DOT_EXE from Products.DCWorkflowGraph.config import DOT_EXE
from Products.DCWorkflowGraph.DCWorkflowGraph import bin_search, getGraph from Products.DCWorkflowGraph.DCWorkflowGraph import bin_search, getGraph
from Products.DCWorkflow.States import StateDefinition as DCWorkflowState
from Products.CMFCore.WorkflowCore import ObjectDeleted
from Products.CMFCore.WorkflowCore import ObjectMoved
from Products.DCWorkflow.utils import Message as _
from Products.ERP5Type.Utils import UpperCase from Products.ERP5Type.Utils import UpperCase
from Acquisition import aq_base from Acquisition import aq_base
from DateTime import DateTime from DateTime import DateTime
...@@ -59,6 +70,7 @@ class Workflow(XMLObject): ...@@ -59,6 +70,7 @@ class Workflow(XMLObject):
managed_permission_list = () managed_permission_list = ()
managed_role = () managed_role = ()
erp5_permission_roles = {} # { permission: [role] or (role,) } erp5_permission_roles = {} # { permission: [role] or (role,) }
manager_bypass = 0
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
...@@ -160,10 +172,48 @@ class Workflow(XMLObject): ...@@ -160,10 +172,48 @@ class Workflow(XMLObject):
### zwj: upper line may meet problems when there are other Base categories. ### zwj: upper line may meet problems when there are other Base categories.
if sdef is None: if sdef is None:
return 0 return 0
if transition in sdef.getDestinationValueList(): if (transition in sdef.getDestinationValueList() and
self._checkTransitionGuard(transition, document) and
transition.trigger_type == TRIGGER_WORKFLOW_METHOD
):
return 1 return 1
return 0 return 0
security.declarePrivate('isActionSupported')
def isActionSupported(self, document, action, **kw):
'''
Returns a true value if the given action name
is possible in the current state.
'''
sdef = document._getDefaultAcquiredValue(self.getStateBaseCategory())
if sdef is None:
return 0
if action in sdef.getDestinationValueList():
tdef = self._getOb(action, None)
if (tdef is not None and
tdef.trigger_type == TRIGGER_USER_ACTION and
self._checkTransitionGuard(tdef, document, **kw)):
return 1
return 0
def _checkTransitionGuard(self, tdef, document, **kw):
guard = tdef.getGuard()
if guard is None:
return 1
if guard.check(getSecurityManager(), self, document, **kw):
return 1
return 0
def _findAutomaticTransition(self, document, sdef):
tdef = None
for tid in sdef.getDestinationIdList():
t = self._getOb(id=tid)
if t is not None and t.trigger_type == TRIGGER_AUTOMATIC:
if self._checkTransitionGuard(t, document):
tdef = t
break
return tdef
### zwj: following parts related to the security features ### zwj: following parts related to the security features
security.declarePrivate('updateRoleMappingsFor') security.declarePrivate('updateRoleMappingsFor')
...@@ -197,6 +247,55 @@ class Workflow(XMLObject): ...@@ -197,6 +247,55 @@ class Workflow(XMLObject):
def getRoleList(self): def getRoleList(self):
return sorted(self.getPortalObject().getDefaultModule('acl_users').valid_roles()) return sorted(self.getPortalObject().getDefaultModule('acl_users').valid_roles())
security.declarePrivate('doActionFor')
def doActionFor(self, document, action, *args, **kw):
sdef = document._getDefaultAcquiredValue(self.getStateBaseCategory())
if sdef is None:
raise WorkflowException(_(u'Object is in an undefined state.'))
if self.isActionSupported(document, action, **kw):
wf_id = self.getId()
if wf_id is None:
raise WorkflowException(
_(u'Requested workflow definition not found.'))
tdef = self._getOb(id=action)
### check again the action object is available
if tdef not in self.objectValues(portal_type='Transition'):
raise Unauthorized(action)
if tdef is None or tdef.trigger_type != TRIGGER_USER_ACTION:
msg = _(u"Transition '${action_id}' is not triggered by a user "
u"action.", mapping={'action_id': action})
raise WorkflowException(msg)
if not self._checkTransitionGuard(tdef, document, **kw):
raise Unauthorized(action)
### execute action
self._changeStateOf(document, tdef)
def _changeStateOf(self, document, tdef=None, kwargs=None):
'''
Changes state. Can execute multiple transitions if there are
automatic transitions. tdef set to None means the object
was just created.
'''
moved_exc = None
while 1:
try:
sdef = tdef.execute(document, kwargs)
except ObjectMoved, moved_exc:
document = moved_exc.getNewObject()
state_bc_id = self.getStateBaseCategory()
status_dict = self.getCurrentStatusDict(document)
sdef = self._getOb(status_dict[state_bc_id])
# Re-raise after all transitions.
if sdef is None:
break
tdef = self._findAutomaticTransition(document, sdef)
if tdef is None:
# No more automatic transitions.
break
# Else continue.
if moved_exc is not None:
# Re-raise.
raise moved_exc
### Security feature end ### Security feature end
########### ###########
......
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