[Zope-CVS] CVS: Packages3/workflow/stateful - configure.zcml:1.2 definition.py:1.3 instance.py:1.3
Ulrich Eck
ueck@net-labs.de
Thu, 6 Feb 2003 17:03:40 -0500
Update of /cvs-repository/Packages3/workflow/stateful
In directory cvs.zope.org:/tmp/cvs-serv23752/stateful
Modified Files:
configure.zcml definition.py instance.py
Log Message:
Next round in Stateful workflow implementation:
- Transitions:
+ Conditions based on TALES Expressions work
- Permissions are implemented but tests do not work yet (tests disabled)
- Instance:
+ Relevant-Data based on Schema basically works (schema written as persistent module)
- Permissions for dataaccess not yet implemented
- BrowserViews:
- basic setup for ManagementInterface made, no functionality yet
- extensive tests for the instance written.
=== Packages3/workflow/stateful/configure.zcml 1.1 => 1.2 ===
--- Packages3/workflow/stateful/configure.zcml:1.1 Tue Feb 4 16:42:18 2003
+++ Packages3/workflow/stateful/configure.zcml Thu Feb 6 17:03:06 2003
@@ -1,15 +1,34 @@
<zopeConfigure
xmlns="http://namespaces.zope.org/zope">
- <content class="zope.app.workflow.stateful.contentworkflow.ContentWorkflowsUtility">
- <require
+<content class="zope.app.workflow.stateful.definition.StatefulProcessDefinition">
+ <factory
+ id="StatefulProcessDefinition"
permission="zope.ManageServices"
- interface="zope.app.interfaces.workflow.stateful.IContentWorkflowsUtility"
/>
- <factory
- id="zope.app.workflow.stateful.contentworkflow.ContentWorkflowsUtility"
+ <require
permission="zope.ManageServices"
+ interface="zope.app.interfaces.workflow.stateful.IStatefulProcessDefinition"
/>
- </content>
+ <implements
+ interface="zope.app.interfaces.annotation.IAttributeAnnotatable"
+ />
+</content>
+
+
+<!-- ContentWorkflowsUtility
+
+<content class="zope.app.workflow.stateful.contentworkflow.ContentWorkflowsUtility">
+ <require
+ permission="zope.ManageServices"
+ interface="zope.app.interfaces.workflow.stateful.IContentWorkflowsUtility"
+ />
+ <factory
+ id="zope.app.workflow.stateful.contentworkflow.ContentWorkflowsUtility"
+ permission="zope.ManageServices"
+ />
+</content>
+
+-->
</zopeConfigure>
=== Packages3/workflow/stateful/definition.py 1.2 => 1.3 ===
--- Packages3/workflow/stateful/definition.py:1.2 Wed Feb 5 20:09:31 2003
+++ Packages3/workflow/stateful/definition.py Thu Feb 6 17:03:06 2003
@@ -18,12 +18,15 @@
"""
__metaclass__ = type
+from types import StringTypes
from persistence import Persistent
from persistence.dict import PersistentDict
from zope.proxy.context import ContextMethod, ContextWrapper
from zope.proxy.context import getWrapperData
+from zope.component import getServiceManager
+
from zope.app.interfaces.workflow import IProcessDefinition
from zope.app.interfaces.workflow.stateful import IStatefulProcessDefinition
from zope.app.interfaces.workflow.stateful import IState, ITransition
@@ -42,6 +45,7 @@
__implements__ = IState
+
class StatesContainer(ProcessDefinitionElementContainer):
"""Container that stores States.
"""
@@ -54,11 +58,13 @@
__implements__ = ITransition
- def __init__(self, source, destination, condition):
+ def __init__(self, source, destination, condition=None, permission=None,
+ name=None, description=None):
super(Transition, self).__init__()
self.__source = source
self.__destination = destination
self.__condition = condition
+ self.__permission = permission
sourceState = property(lambda self: self.__source)
@@ -66,6 +72,10 @@
condition = property(lambda self: self.__condition)
+ permission = property(lambda self: self.__permission)
+
+
+
class TransitionsContainer(ProcessDefinitionElementContainer):
"""Container that stores Transitions.
@@ -86,13 +96,14 @@
initial = State()
self.__states.setObject(self.getInitialStateName(), initial)
self.__transitions = TransitionsContainer()
-
+ self.__schema = None
############################################################
# Implementation methods for interface
# zope.app.interfaces.workflow.stateful.IStatefulProcessDefinition
+
states = property(lambda self: ContextWrapper(self.__states, self))
transitions = property(lambda self: ContextWrapper(self.__transitions,
@@ -112,7 +123,8 @@
def getStateNames(self):
return self.states.keys()
-
+
+ # XXX This shouldn't be hardcoded
def getInitialStateName(self):
return 'INITIAL'
@@ -140,6 +152,16 @@
return pi_obj
createProcessInstance = ContextMethod(createProcessInstance)
+ def setSchema(self, schema):
+ self.__schema = schema
+
+ def getSchema(self):
+ schema = self.__schema
+ if type(schema) in StringTypes:
+ sm = getServiceManager(self)
+ return sm.resolve(schema)
+ return schema
+ getSchema = ContextMethod(getSchema)
#
############################################################
=== Packages3/workflow/stateful/instance.py 1.2 => 1.3 ===
--- Packages3/workflow/stateful/instance.py:1.2 Wed Feb 5 20:09:31 2003
+++ Packages3/workflow/stateful/instance.py Thu Feb 6 17:03:06 2003
@@ -21,14 +21,32 @@
from persistence import Persistent
-
+from zope.exceptions import Unauthorized
from zope.component import getService
from zope.proxy.context import ContextMethod
+from zope.proxy.context import ContextWrapper,ContextAware
+from zope.security.management import getSecurityManager
+from zope.pagetemplate.engine import Engine
+from zope.schema import getFields
from zope.app.interfaces.workflow.stateful import IStatefulProcessInstance
from zope.app.workflow.instance import ProcessInstance
+class StateChangeInfo:
+ """Immutable StateChangeInfo.
+ """
+
+ def __init__(self, transition):
+ self.__old_state = transition.sourceState
+ self.__new_state = transition.destinationState
+
+ old_state = property(lambda self: self.__old_state)
+
+ new_state = property(lambda self: self.__new_state)
+
+
+
class StatefulProcessInstance(ProcessInstance, Persistent):
"""Stateful Workflow ProcessInstance.
"""
@@ -39,23 +57,44 @@
############################################################
# Implementation methods for interface
# zope.app.interfaces.workflow.IStatefulProcessInstance
+
+
+ data = property(lambda self: ContextWrapper(self._data, self))
def initialize(self):
pd = self._getProcessDefinition()
self._status = pd.getInitialStateName()
- # create relevant-data, schema and permissions here
+ # create relevant-data
+ schema = pd.getSchema()
+ self._data = self._buildRelevantData(schema)
+ # setup permission on data
+
initialize = ContextMethod(initialize)
def getOutgoingTransitions(self):
ret = []
pd = self._getProcessDefinition()
+ sm = getSecurityManager()
+
for name, trans in pd.transitions.items():
if self.status == trans.sourceState:
- # evaluate trans.condition
- # and check permission
- if 1:
- ret.append(name)
+ # check permissions
+ if trans.permission:
+ if not sm.checkPermission(trans.permission, self):
+ continue
+
+ # evaluate conditions
+ if trans.condition is not None:
+ try:
+ include = self._evaluateCondition(trans)
+ except Unauthorized:
+ include = 0
+ if not include:
+ continue
+
+ # append transition name
+ ret.append(name)
return ret
getOutgoingTransitions = ContextMethod(getOutgoingTransitions)
@@ -78,3 +117,33 @@
svc = getService(self, "Workflows")
return svc.getProcessDefinition(self.processDefinitionName)
_getProcessDefinition = ContextMethod(_getProcessDefinition)
+
+
+
+ def _getContext(self, transition):
+ ctx = {}
+ # data should be readonly for condition-evaluation
+ ctx['data'] = self.data
+ ctx['principal'] = getSecurityManager().getPrincipal()
+ ctx['state_change'] = StateChangeInfo(transition)
+ return ctx
+
+ def _evaluateCondition(self, transition):
+ """Evaluate a condition in context of relevant-data.
+ """
+ expr = Engine.compile(transition.condition)
+ return expr(Engine.getContext( contexts=self._getContext(transition) ))
+
+
+ def _buildRelevantData(self, schema):
+ """Create a new data object and initialize with Schema defaults.
+ """
+ class RelevantData(ContextAware):
+ __implements__ = schema
+
+ data = RelevantData()
+ if schema is not None:
+ for name, field in getFields(schema).items():
+ setattr(data, name, field.default)
+ return data
+