provide 'actors' and 'condition' attributes for more control on actions/transitions

This commit is contained in:
Helmut Merz 2013-07-18 13:26:25 +02:00
parent e6df09d4dc
commit 68ed9d878b
4 changed files with 76 additions and 5 deletions

View file

@ -2,8 +2,6 @@
Stateful Objects
================
($Id$)
>>> from cybertools.stateful.definition import StatesDefinition
>>> from cybertools.stateful.definition import State, Transition
>>> from cybertools.stateful.definition import registerStatesDefinition
@ -13,7 +11,9 @@ We start with a simple demonstration class that provides stateful
behaviour directly.
>>> class Demo(Stateful):
... pass
... currentActors = None
... def getActors(self):
... return self.currentActors
>>> demo = Demo()
@ -57,6 +57,43 @@ of the current state we get an error.
>>> demo.getState()
'draft'
Check condition
---------------
>>> def checkIfEmpty(obj):
... return getattr(obj, 'empty', True)
>>> removeAction = demo.getStatesDefinition().transitions.remove
>>> removeAction.condition = checkIfEmpty
>>> removeAction in demo.getAvailableTransitions()
True
>>> demo.empty = False
>>> removeAction in demo.getAvailableTransitions()
False
Check actors
------------
>>> removeAction.actors = ['master']
>>> demo.getActors()
>>> demo.empty = True
>>> removeAction in demo.getAvailableTransitionsForUser()
True
>>> demo.currentActors = ['dummy']
>>> demo.getActors()
['dummy']
>>> removeAction in demo.getAvailableTransitionsForUser()
False
>>> demo.currentActors = ['master']
>>> removeAction in demo.getAvailableTransitionsForUser()
True
Stateful Adapters
=================
@ -94,3 +131,4 @@ back the state that is stored with the object.
>>> statefulDemo = IStateful(demo)
>>> statefulDemo.getState()
'finished'

View file

@ -82,6 +82,9 @@ class Stateful(object):
def getStatesDefinition(self):
return statesDefinitions.get(self.statesDefinition, None)
def getActors(self):
return None
def notify(self, transition, previousState):
""" To be implemented by subclass.
"""

View file

@ -55,6 +55,8 @@ class Action(object):
allowed = True
permission = None
roles = []
actors = []
condition = None
doBefore = []
schema = None
@ -69,8 +71,6 @@ class Transition(Action):
implements(ITransition)
actors = None
def __init__(self, name, title, targetState, **kw):
super(Transition, self).__init__(name, title, **kw)
self.targetState = targetState
@ -123,12 +123,25 @@ class StatesDefinition(object):
def isAllowed(self, action, obj):
if not action.allowed:
return False
if action.condition and not action.condition(obj):
return False
if not self.checkActors(action.actors, obj):
return False
if not self.checkRoles(action.roles, obj):
return False
if not self.checkPermission(action.permission, obj):
return False
return True
def checkActors(self, actors, obj):
stfActors = obj.getActors()
if stfActors is None:
return True
for actor in actors:
if actor in stfActors:
return True
return False
def checkRoles(self, roles, obj):
return True

View file

@ -50,6 +50,12 @@ class IAction(Interface):
'to execute this action; no check when empty.')
permission = Attribute('The name of a permission that is needed for '
'executing this action; no check when empty.')
actors = Attribute('A collection of names of actors or groups that should be '
'able to execute this action; no check when empty. '
'See the IStateful.getActors().')
condition = Attribute('A boolean function with a stateful object as '
'parameter. The action is only allowed if return value '
'is True. No check when condition is None.')
schema = Attribute('An optional schema (a sequence of field specifications) '
'that provides information on fields to be shown in a '
'form used for executing the action.')
@ -97,6 +103,17 @@ class IStateful(Interface):
for the current state.
"""
def getActors():
""" Return a collection of names of actors or groups that will be
used for checking if a certain transition is allowed. May be
None in which case not checking should be applied.
"""
def notify(transition, previousState):
""" This method will be called upon completion of a transition.
"""
request = Attribute('Optional publication request.')