Commit e4cf8f6a authored by Jens Vagelpohl's avatar Jens Vagelpohl

- exportimport: Support for instance creation guards and manager

  bypass added.
  (https://bugs.launchpad.net/zope-cmf/+bug/308947)
parent 78560857
......@@ -4,6 +4,10 @@ Products.DCWorkflow Changelog
2.2.0 (unreleased)
------------------
- exportimport: Support for instance creation guards and manager
bypass added.
(https://bugs.launchpad.net/zope-cmf/+bug/308947)
- Cleaned up / normalized imports:
o Don't import from Globals; instead, use real locations.
......
......@@ -27,6 +27,7 @@ from zope.component import adapts
from Products.CMFCore.Expression import Expression
from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
from Products.DCWorkflow.Guard import Guard
from Products.DCWorkflow.interfaces import IDCWorkflowDefinition
from Products.DCWorkflow.permissions import ManagePortal
from Products.DCWorkflow.utils import _xmldir
......@@ -67,11 +68,15 @@ class DCWorkflowDefinitionBodyAdapter(BodyAdapterBase):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = wfdc.parseWorkflowXML(body, encoding)
_initDCWorkflow( self.context
, title
, description
, manager_bypass
, creation_guard
, state_variable
, initial_state
, states
......@@ -157,6 +162,8 @@ class WorkflowDefinitionConfigurator( Implicit ):
except ValueError:
# Don't fail on export files that do not have the description field!
description = ''
manager_bypass = _getNodeAttributeBoolean(root, 'manager_bypass')
creation_guard = _extractCreationGuard(root, encoding)
state_variable = _getNodeAttribute( root, 'state_variable', encoding )
initial_state = _getNodeAttribute( root, 'initial_state', encoding )
......@@ -178,6 +185,8 @@ class WorkflowDefinitionConfigurator( Implicit ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
)
security.declarePrivate( '_workflowConfig' )
......@@ -197,9 +206,11 @@ class WorkflowDefinitionConfigurator( Implicit ):
o The following keys will be added to 'workflow_info':
'creation_guard' -- the guard of 'Instance creation conditions'
'permissions' -- a list of names of permissions managed
by the workflow
'state_variable' -- the name of the workflow's "main"
state variable
......@@ -221,6 +232,8 @@ class WorkflowDefinitionConfigurator( Implicit ):
'script_info' -- a list of mappings describing the scripts which
provide added business logic (see '_extractScripts').
"""
workflow_info[ 'manager_bypass' ] = workflow.manager_bypass
workflow_info[ 'creation_guard' ] = self._extractCreationGuard(workflow)
workflow_info[ 'state_variable' ] = workflow.state_var
workflow_info[ 'initial_state' ] = workflow.initial_state
workflow_info[ 'permissions' ] = workflow.permissions
......@@ -231,6 +244,20 @@ class WorkflowDefinitionConfigurator( Implicit ):
workflow_info[ 'worklist_info' ] = self._extractWorklists( workflow )
workflow_info[ 'script_info' ] = self._extractScripts( workflow )
security.declarePrivate('_extractCreationGuard')
def _extractCreationGuard(self, workflow):
""" Return a mapping describing 'Instance creation conditions'
if 'creation_guard' is initialized or None
"""
guard = workflow.creation_guard
if guard is not None :
info = { 'guard_permissions' : guard.permissions
, 'guard_roles' : guard.roles
, 'guard_groups' : guard.groups
, 'guard_expr' : guard.getExprText()
}
return info
security.declarePrivate( '_extractVariables' )
def _extractVariables( self, workflow ):
......@@ -621,6 +648,15 @@ def _getScriptFilename( workflow_id, script_id, meta_type ):
return 'workflows/%s/scripts/%s.%s' % ( wf_dir, script_id, suffix )
def _extractCreationGuard(root, encoding=None) :
icc = root.getElementsByTagName('instance-creation-conditions')
assert len(icc) <= 1
if icc :
parent = icc[0]
return _extractGuardNode(parent, encoding)
else :
return None
def _extractStateNodes( root, encoding=None ):
result = []
......@@ -959,6 +995,8 @@ _METATYPE_SUFFIXES = \
def _initDCWorkflow( workflow
, title
, description
, manager_bypass
, creation_guard
, state_variable
, initial_state
, states
......@@ -973,6 +1011,7 @@ def _initDCWorkflow( workflow
"""
workflow.title = title
workflow.description = description
workflow.manager_bypass = manager_bypass
workflow.state_var = state_variable
workflow.initial_state = initial_state
......@@ -980,6 +1019,7 @@ def _initDCWorkflow( workflow
permissions.sort()
workflow.permissions = tuple(permissions)
_initDCWorkflowCreationGuard( workflow, creation_guard )
_initDCWorkflowVariables( workflow, variables )
_initDCWorkflowStates( workflow, states )
_initDCWorkflowTransitions( workflow, transitions )
......@@ -987,6 +1027,21 @@ def _initDCWorkflow( workflow
_initDCWorkflowScripts( workflow, scripts, context )
def _initDCWorkflowCreationGuard( workflow, guard ):
"""Initialize Instance creation conditions guard
"""
if guard is None :
workflow.creation_guard = None
else :
props = { 'guard_roles' : ';'.join( guard[ 'roles' ] )
, 'guard_permissions' : ';'.join( guard[ 'permissions' ] )
, 'guard_groups' : ';'.join( guard[ 'groups' ] )
, 'guard_expr' : guard[ 'expression' ]
}
g = Guard()
g.changeFromProperties(props)
workflow.creation_guard = g
def _initDCWorkflowVariables( workflow, variables ):
""" Initialize DCWorkflow variables
......
......@@ -2,7 +2,8 @@
<dc-workflow workflow_id="default_workflow"
title="CMF default workflow [Revision 2]"
state_variable="review_state"
initial_state="visible">
initial_state="visible"
manager_bypass="False">
<permission>Access contents information</permission>
<permission>Modify portal content</permission>
<permission>View</permission>
......
......@@ -29,6 +29,7 @@ from Products.CMFCore.exportimport.tests.test_workflow \
import _WorkflowSetup as WorkflowSetupBase
from Products.CMFCore.testing import DummyWorkflow
from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
from Products.DCWorkflow.Guard import Guard
from Products.DCWorkflow.testing import ExportImportZCMLLayer
from Products.DCWorkflow.Transitions import TRIGGER_USER_ACTION
from Products.DCWorkflow.Transitions import TRIGGER_AUTOMATIC
......@@ -189,6 +190,12 @@ class _WorkflowSetup(WorkflowSetupBase):
raise ValueError, 'Unknown script type: %s' % v[ 0 ]
dcworkflow.scripts._setObject( k, script )
def _initCreationGuard(self, dcworkflow) :
props = self._genGuardProps(*_CREATION_GUARD)
g = Guard()
g.changeFromProperties(props)
dcworkflow.creation_guard = g
class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
......@@ -465,6 +472,13 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, expected[ 2 ] % WF_ID )
else:
self.assertEqual( info[ 'filename' ], expected[ 2 ] )
def test_getWorkflowInfo_dcworkflow_creation_guard(self) :
WF_ID = 'dcworkflow_creation_guard'
site = self._initSite()
dcworkflow = self._initDCWorkflow( WF_ID )
self._initCreationGuard(dcworkflow)
def test_generateXML_empty( self ):
......@@ -596,6 +610,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML( _EMPTY_WORKFLOW_EXPORT
% ( WF_ID
, WF_TITLE
......@@ -633,6 +649,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML(
_NORMAL_WORKFLOW_EXPORT
% { 'workflow_id' : WF_ID
......@@ -670,6 +688,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML(
_NORMAL_WORKFLOW_EXPORT
% { 'workflow_id' : WF_ID
......@@ -736,6 +756,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML(
_NORMAL_WORKFLOW_EXPORT
% { 'workflow_id' : WF_ID
......@@ -805,6 +827,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML(
_NORMAL_WORKFLOW_EXPORT
% { 'workflow_id' : WF_ID
......@@ -883,6 +907,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML(
_NORMAL_WORKFLOW_EXPORT
% { 'workflow_id' : WF_ID
......@@ -946,6 +972,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML(
_NORMAL_WORKFLOW_EXPORT
% { 'workflow_id' : WF_ID
......@@ -983,6 +1011,8 @@ class WorkflowDefinitionConfiguratorTests( _WorkflowSetup, _GuardChecker ):
, permissions
, scripts
, description
, manager_bypass
, creation_guard
) = configurator.parseWorkflowXML(
_NORMAL_WORKFLOW_EXPORT
% { 'workflow_id' : WF_ID
......@@ -1251,6 +1281,13 @@ _WF_SCRIPTS = \
)
}
_CREATION_GUARD = \
(('Add portal content', 'Manage portal')
,('Owner', 'Manager')
,('group_readers', 'group_members')
,'python:len(here.objectIds() <= 10)'
)
_NORMAL_TOOL_EXPORT = """\
<?xml version="1.0"?>
<object name="portal_workflow" meta_type="Dummy Workflow Tool">
......@@ -1293,7 +1330,8 @@ _EMPTY_WORKFLOW_EXPORT = """\
title="%s"
description="%s"
state_variable="state"
initial_state="%s">
initial_state="%s"
manager_bypass="0">
</dc-workflow>
"""
......@@ -1305,7 +1343,8 @@ _OLD_WORKFLOW_EXPORT = """\
workflow_id="%(workflow_id)s"
title="%(title)s"
state_variable="state"
initial_state="%(initial_state)s">
initial_state="%(initial_state)s"
manager_bypass="0">
<permission>Open content for modifications</permission>
<permission>Modify content</permission>
<permission>Query history</permission>
......@@ -1549,7 +1588,8 @@ _NORMAL_WORKFLOW_EXPORT = """\
title="%(title)s"
description="%(description)s"
state_variable="state"
initial_state="%(initial_state)s">
initial_state="%(initial_state)s"
manager_bypass="0">
<permission>Open content for modifications</permission>
<permission>Modify content</permission>
<permission>Query history</permission>
......@@ -1791,6 +1831,26 @@ _NORMAL_WORKFLOW_EXPORT = """\
</dc-workflow>
"""
_CREATION_GUARD_WORKFLOW_EXPORT = """\
<?xml version="1.0"?>
<dc-workflow
workflow_id="%s"
title="%s"
description="%s"
state_variable="state"
initial_state="%s"
manager_bypass="1">
<instance-creation-conditions>
<guard>
<guard-permission>Add portal content</guard-permission>
<guard-role>Owner</guard-role>
<guard-group>group_members</guard-group>
<guard-expression>python:len(here.objectIds() &lt;= 10)</guard-expression>
</guard>
</instance-creation-conditions>
</dc-workflow>
"""
class Test_exportWorkflow(_WorkflowSetup, _GuardChecker):
......
......@@ -11,8 +11,29 @@
tal:attributes="workflow_id info/id;
title info/title;
description info/description;
manager_bypass info/manager_bypass;
state_variable info/state_variable;
initial_state info/initial_state">
<instance-creation-conditions tal:define="creation_guard info/creation_guard" tal:condition="creation_guard">
<guard
><tal:case tal:condition="creation_guard/guard_permissions">
<guard-permission
tal:repeat="permission creation_guard/guard_permissions"
tal:content="permission">PERMISSION</guard-permission></tal:case
><tal:case tal:condition="creation_guard/guard_roles">
<guard-role
tal:repeat="role creation_guard/guard_roles"
tal:content="role">ROLE</guard-role></tal:case
><tal:case tal:condition="creation_guard/guard_groups">
<guard-group
tal:repeat="group creation_guard/guard_groups"
tal:content="group">GROUP</guard-group></tal:case
><tal:case tal:condition="creation_guard/guard_expr">
<guard-expression
tal:content="creation_guard/guard_expr">EXPRESSION</guard-expression
></tal:case>
</guard>
</instance-creation-conditions>
<permission
tal:repeat="permission info/permissions"
tal:content="permission">PERMISSION</permission>
......
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