Commit 6dc2151f authored by Jean-Paul Smets's avatar Jean-Paul Smets

*** empty log message ***


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@1182 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 7cca32e1
...@@ -34,14 +34,10 @@ from Products.CMFCore.CMFCorePermissions import ManagePortal ...@@ -34,14 +34,10 @@ from Products.CMFCore.CMFCorePermissions import ManagePortal
from Products.DCWorkflow.ContainerTab import ContainerTab from Products.DCWorkflow.ContainerTab import ContainerTab
from Products.DCWorkflow.Guard import Guard from Products.DCWorkflow.Guard import Guard
from Products.DCWorkflow.Expression import Expression from Products.DCWorkflow.Expression import Expression
from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC, TRIGGER_WORKFLOW_METHOD
from Products.ERP5 import _dtmldir from Products.ERP5 import _dtmldir
TRIGGER_AUTOMATIC = 0
TRIGGER_USER_ACTION = 1 # useless for interaction
TRIGGER_WORKFLOW_METHOD = 2
class InteractionDefinition (SimpleItem): class InteractionDefinition (SimpleItem):
meta_type = 'Workflow Interaction' meta_type = 'Workflow Interaction'
...@@ -51,14 +47,16 @@ class InteractionDefinition (SimpleItem): ...@@ -51,14 +47,16 @@ class InteractionDefinition (SimpleItem):
title = '' title = ''
description = '' description = ''
new_state_id = '' new_state_id = ''
trigger_type = TRIGGER_USER_ACTION trigger_type = TRIGGER_WORKFLOW_METHOD
guard = None guard = None
actbox_name = '' actbox_name = ''
actbox_url = '' actbox_url = ''
actbox_category = 'workflow' actbox_category = 'workflow'
var_exprs = None # A mapping. var_exprs = None # A mapping.
script_name = None # Executed before transition script_name = () # Executed before transition
after_script_name = None # Executed after transition after_script_name = () # Executed after transition
activate_script_name = () # Executed as activity
method_id = None
manage_options = ( manage_options = (
{'label': 'Properties', 'action': 'manage_properties'}, {'label': 'Properties', 'action': 'manage_properties'},
...@@ -115,20 +113,29 @@ class InteractionDefinition (SimpleItem): ...@@ -115,20 +113,29 @@ class InteractionDefinition (SimpleItem):
manage_tabs_message=manage_tabs_message, manage_tabs_message=manage_tabs_message,
) )
def setProperties(self, title, new_state_id, def setProperties(self, title,
trigger_type=TRIGGER_USER_ACTION, script_name='', portal_type_filter=None,
after_script_name='', trigger_type=TRIGGER_AUTOMATIC,
script_name=(),
after_script_name=(),
activate_script_name=(),
actbox_name='', actbox_url='', actbox_name='', actbox_url='',
actbox_category='workflow', actbox_category='workflow',
method_id=None,
props=None, REQUEST=None, description=''): props=None, REQUEST=None, description=''):
''' '''
Update transition properties
XXX - then make sure that method_id is WorkflowMethod for portal_type_filter
XXX - this will likely require dynamic
''' '''
self.method_id = method_id
self.portal_type_filter = portal_type_filter
self.title = str(title) self.title = str(title)
self.description = str(description) self.description = str(description)
self.new_state_id = str(new_state_id)
self.trigger_type = int(trigger_type) self.trigger_type = int(trigger_type)
self.script_name = str(script_name) self.script_name = map(lambda x: str(x), script_name)
self.after_script_name = str(after_script_name) self.after_script_name = map(lambda x: str(x), after_script_name)
self.activate_script_name = map(lambda x: str(x), activate_script_name)
g = Guard() g = Guard()
if g.changeFromProperties(props or REQUEST): if g.changeFromProperties(props or REQUEST):
self.guard = g self.guard = g
......
...@@ -18,16 +18,21 @@ ...@@ -18,16 +18,21 @@
import Globals import Globals
import App import App
from AccessControl import ClassSecurityInfo from AccessControl import getSecurityManager, ClassSecurityInfo
from Products.CMFCore.utils import getToolByName, _getAuthenticatedUser from Products.CMFCore.utils import getToolByName, _getAuthenticatedUser
from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface
from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire
from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC, TRIGGER_WORKFLOW_METHOD
from Products.CMFCore.WorkflowCore import WorkflowException, \
ObjectDeleted, ObjectMoved
from Products.DCWorkflow.Expression import StateChangeInfo, createExprContext
from Products.CMFCore.WorkflowTool import addWorkflowFactory from Products.CMFCore.WorkflowTool import addWorkflowFactory
from Products.CMFActivity.ActiveObject import ActiveObject
from zLOG import LOG from zLOG import LOG
class InteractionWorkflowDefinition (DCWorkflowDefinition): class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
""" """
The InteractionTool implements portal object The InteractionTool implements portal object
interaction policies. interaction policies.
...@@ -95,7 +100,6 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition): ...@@ -95,7 +100,6 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition):
{'label': 'Interactions', 'action': 'interactions/manage_main'}, {'label': 'Interactions', 'action': 'interactions/manage_main'},
{'label': 'Variables', 'action': 'variables/manage_main'}, {'label': 'Variables', 'action': 'variables/manage_main'},
{'label': 'Scripts', 'action': 'scripts/manage_main'}, {'label': 'Scripts', 'action': 'scripts/manage_main'},
{'label': 'Permissions', 'action': 'manage_permissions'},
) + App.Undo.UndoSupport.manage_options ) + App.Undo.UndoSupport.manage_options
def __init__(self, id): def __init__(self, id):
...@@ -109,6 +113,313 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition): ...@@ -109,6 +113,313 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition):
from Products.DCWorkflow.Scripts import Scripts from Products.DCWorkflow.Scripts import Scripts
self._addObject(Scripts('scripts')) self._addObject(Scripts('scripts'))
def _executeTransition(self, ob, tdef=None, kwargs=None):
'''
Private method.
Puts object in a new state.
'''
sci = None
econtext = None
moved_exc = None
# Figure out the old and new states.
old_sdef = self._getWorkflowStateOf(ob)
old_state = old_sdef.getId()
if tdef is None:
new_state = self.initial_state
former_status = {}
else:
new_state = tdef.new_state_id
if not new_state:
# Stay in same state.
new_state = old_state
former_status = self._getStatusOf(ob)
new_sdef = self.states.get(new_state, None)
if new_sdef is None:
raise WorkflowException, (
'Destination state undefined: ' + new_state)
# Execute the "before" script.
if tdef is not None:
for script_name in tdef.script_name:
script = self.scripts[script_name]
# Pass lots of info to the script in a single parameter.
sci = StateChangeInfo(
ob, self, former_status, tdef, old_sdef, new_sdef, kwargs)
try:
script(sci) # May throw an exception.
except ObjectMoved, moved_exc:
ob = moved_exc.getNewObject()
# Re-raise after transition
# Update variables.
state_values = new_sdef.var_values
if state_values is None: state_values = {}
tdef_exprs = None
if tdef is not None: tdef_exprs = tdef.var_exprs
if tdef_exprs is None: tdef_exprs = {}
status = {}
for id, vdef in self.variables.items():
if not vdef.for_status:
continue
expr = None
if state_values.has_key(id):
value = state_values[id]
elif tdef_exprs.has_key(id):
expr = tdef_exprs[id]
elif not vdef.update_always and former_status.has_key(id):
# Preserve former value
value = former_status[id]
else:
if vdef.default_expr is not None:
expr = vdef.default_expr
else:
value = vdef.default_value
if expr is not None:
# Evaluate an expression.
if econtext is None:
# Lazily create the expression context.
if sci is None:
sci = StateChangeInfo(
ob, self, former_status, tdef,
old_sdef, new_sdef, kwargs)
econtext = createExprContext(sci)
value = expr(econtext)
status[id] = value
# Update state.
status[self.state_var] = new_state
tool = aq_parent(aq_inner(self))
tool.setStatusOf(self.id, ob, status)
# Update role to permission assignments.
self.updateRoleMappingsFor(ob)
# Execute the "after" script.
if tdef is not None:
for after_script_name in tdef.after_script_name:
script = self.scripts[after_script_name]
# Pass lots of info to the script in a single parameter.
sci = StateChangeInfo(
ob, self, status, tdef, old_sdef, new_sdef, kwargs)
script(sci) # May throw an exception.
# Execute the "activate" script.
if tdef is not None:
for after_script_name in tdef.activate_script_name:
script = self.scripts[after_script_name]
# Pass lots of info to the script in a single parameter.
sci = StateChangeInfo(
ob.activate(activity='SQLQueue'), None, status, tdef, old_sdef, new_sdef, kwargs)
script(sci) # May throw an exception.
# Return the new state object.
if moved_exc is not None:
# Propagate the notification that the object has moved.
raise moved_exc
else:
return new_sdef
security.declarePrivate('listObjectActions')
def listObjectActions(self, info):
return []
security.declarePrivate('isInfoSupported')
def isInfoSupported(self, ob, name):
'''
Returns a true value if the given info name is supported.
'''
vdef = self.variables.get(name, None)
if vdef is None:
return 0
return 1
security.declarePrivate('getInfoFor')
def getInfoFor(self, ob, name, default):
'''
Allows the user to request information provided by the
workflow. This method must perform its own security checks.
'''
vdef = self.variables[name]
if vdef.info_guard is not None and not vdef.info_guard.check(
getSecurityManager(), self, ob):
return default
status = self._getStatusOf(ob)
if status is not None and status.has_key(name):
value = status[name]
# Not set yet. Use a default.
elif vdef.default_expr is not None:
ec = createExprContext(StateChangeInfo(ob, self, status))
value = vdef.default_expr(ec)
else:
value = vdef.default_value
return value
security.declarePrivate('isWorkflowMethodSupported')
def isWorkflowMethodSupported(self, ob, method_id):
'''
Returns a true value if the given workflow is
automatic with the propper method_id
'''
return 0
for t in self.interactions.values():
if t.trigger_type == TRIGGER_WORKFLOW_METHOD:
if t.method_id == method_id:
if t.portal_type_filter is None:
return 1
elif ob.getPortalType() in t.portal_type_filter:
return 1
return 0
security.declarePrivate('wrapWorkflowMethod')
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.
'''
for t in self.interactions.values():
tdef = None
if t.trigger_type == TRIGGER_WORKFLOW_METHOD:
if t.method_id == method_id:
if t.portal_type_filter is None:
tdef = t
elif ob.getPortalType() in t.portal_type_filter:
tdef = t
if tdef is not None:
# Only execute if guard OK
if self._checkTransitionGuard(tdef, ob):
res = apply(func, args, kw)
try:
self._changeStateOf(ob, tdef)
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
security.declarePrivate('notifyBefore')
def notifyBefore(self, ob, action, args=None, kw=None):
'''
Notifies this workflow of an action before it happens,
allowing veto by exception. Unless an exception is thrown, either
a notifySuccess() or notifyException() can be expected later on.
The action usually corresponds to a method name.
'''
for t in self.interactions.values():
tdef = None
if t.trigger_type == TRIGGER_AUTOMATIC:
if t.portal_type_filter is None:
tdef = t
elif ob.getPortalType() in t.portal_type_filter:
tdef = t
elif t.trigger_type == TRIGGER_WORKFLOW_METHOD:
if t.method_id == action:
if t.portal_type_filter is None:
tdef = t
elif ob.getPortalType() in t.portal_type_filter:
tdef = t
if tdef is not None:
former_status = self._getStatusOf(ob)
# Execute the "before" script.
for script_name in tdef.script_name:
script = self.scripts[script_name]
# Pass lots of info to the script in a single parameter.
sci = StateChangeInfo(
ob, self, former_status, tdef, None, None, None)
try:
script(sci) # May throw an exception.
except ObjectMoved, moved_exc:
ob = moved_exc.getNewObject()
# Re-raise after transition
return
security.declarePrivate('notifySuccess')
def notifySuccess(self, ob, action, result, args=None, kw=None):
'''
Notifies this workflow that an action has taken place.
'''
for t in self.interactions.values():
tdef = None
if t.trigger_type == TRIGGER_AUTOMATIC:
if t.portal_type_filter is None:
tdef = t
elif ob.getPortalType() in t.portal_type_filter:
tdef = t
elif t.trigger_type == TRIGGER_WORKFLOW_METHOD:
if t.method_id == action:
if t.portal_type_filter is None:
tdef = t
elif ob.getPortalType() in t.portal_type_filter:
tdef = t
if tdef is not None:
# Update variables.
former_status = self._getStatusOf(ob)
tdef_exprs = tdef.var_exprs
if tdef_exprs is None: tdef_exprs = {}
status = {}
for id, vdef in self.variables.items():
if not vdef.for_status:
continue
expr = None
if tdef_exprs.has_key(id):
expr = tdef_exprs[id]
elif not vdef.update_always and former_status.has_key(id):
# Preserve former value
value = former_status[id]
else:
if vdef.default_expr is not None:
expr = vdef.default_expr
else:
value = vdef.default_value
if expr is not None:
# Evaluate an expression.
if econtext is None:
# Lazily create the expression context.
if sci is None:
sci = StateChangeInfo(
ob, self, former_status, tdef,
None, None, None)
econtext = createExprContext(sci)
value = expr(econtext)
status[id] = value
# Update state.
tool = aq_parent(aq_inner(self))
tool.setStatusOf(self.id, ob, status)
# Execute the "after" script.
for script_name in tdef.after_script_name:
script = self.scripts[script_name]
# Pass lots of info to the script in a single parameter.
sci = StateChangeInfo(
ob, self, status, tdef, None, None, None)
try:
script(sci) # May throw an exception.
except ObjectMoved, moved_exc:
ob = moved_exc.getNewObject()
# Re-raise after transition
# Execute the "after" script.
for script_name in tdef.activate_script_name:
self.activate(activity='SQLQueue').activeScript(script_name, ob.getRelativeUrl(), status, tdef.id)
return
security.declarePrivate('activeScript')
def activeScript(self, script_name, ob_url, status, tdef_id):
script = self.scripts[script_name]
ob = self.restrictedTraverse(ob_url)
tdef = self.interactions.get(tdef_id)
sci = StateChangeInfo(
ob, self, status, tdef, None, None, None)
script(sci)
Globals.InitializeClass(InteractionWorkflowDefinition) Globals.InitializeClass(InteractionWorkflowDefinition)
addWorkflowFactory(InteractionWorkflowDefinition, id='interaction_workflow', addWorkflowFactory(InteractionWorkflowDefinition, id='interaction_workflow',
......
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