Merge branch 'master' into bbmaster
This commit is contained in:
commit
2be1e6df6b
4 changed files with 76 additions and 5 deletions
|
@ -2,8 +2,6 @@
|
||||||
Stateful Objects
|
Stateful Objects
|
||||||
================
|
================
|
||||||
|
|
||||||
($Id$)
|
|
||||||
|
|
||||||
>>> from cybertools.stateful.definition import StatesDefinition
|
>>> from cybertools.stateful.definition import StatesDefinition
|
||||||
>>> from cybertools.stateful.definition import State, Transition
|
>>> from cybertools.stateful.definition import State, Transition
|
||||||
>>> from cybertools.stateful.definition import registerStatesDefinition
|
>>> from cybertools.stateful.definition import registerStatesDefinition
|
||||||
|
@ -13,7 +11,9 @@ We start with a simple demonstration class that provides stateful
|
||||||
behaviour directly.
|
behaviour directly.
|
||||||
|
|
||||||
>>> class Demo(Stateful):
|
>>> class Demo(Stateful):
|
||||||
... pass
|
... currentActors = None
|
||||||
|
... def getActors(self):
|
||||||
|
... return self.currentActors
|
||||||
|
|
||||||
>>> demo = Demo()
|
>>> demo = Demo()
|
||||||
|
|
||||||
|
@ -57,6 +57,43 @@ of the current state we get an error.
|
||||||
>>> demo.getState()
|
>>> demo.getState()
|
||||||
'draft'
|
'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
|
Stateful Adapters
|
||||||
=================
|
=================
|
||||||
|
@ -94,3 +131,4 @@ back the state that is stored with the object.
|
||||||
>>> statefulDemo = IStateful(demo)
|
>>> statefulDemo = IStateful(demo)
|
||||||
>>> statefulDemo.getState()
|
>>> statefulDemo.getState()
|
||||||
'finished'
|
'finished'
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,9 @@ class Stateful(object):
|
||||||
def getStatesDefinition(self):
|
def getStatesDefinition(self):
|
||||||
return statesDefinitions.get(self.statesDefinition, None)
|
return statesDefinitions.get(self.statesDefinition, None)
|
||||||
|
|
||||||
|
def getActors(self):
|
||||||
|
return None
|
||||||
|
|
||||||
def notify(self, transition, previousState):
|
def notify(self, transition, previousState):
|
||||||
""" To be implemented by subclass.
|
""" To be implemented by subclass.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -55,6 +55,8 @@ class Action(object):
|
||||||
allowed = True
|
allowed = True
|
||||||
permission = None
|
permission = None
|
||||||
roles = []
|
roles = []
|
||||||
|
actors = []
|
||||||
|
condition = None
|
||||||
doBefore = []
|
doBefore = []
|
||||||
schema = None
|
schema = None
|
||||||
|
|
||||||
|
@ -69,8 +71,6 @@ class Transition(Action):
|
||||||
|
|
||||||
implements(ITransition)
|
implements(ITransition)
|
||||||
|
|
||||||
actors = None
|
|
||||||
|
|
||||||
def __init__(self, name, title, targetState, **kw):
|
def __init__(self, name, title, targetState, **kw):
|
||||||
super(Transition, self).__init__(name, title, **kw)
|
super(Transition, self).__init__(name, title, **kw)
|
||||||
self.targetState = targetState
|
self.targetState = targetState
|
||||||
|
@ -127,12 +127,25 @@ class StatesDefinition(object):
|
||||||
def isAllowed(self, action, obj):
|
def isAllowed(self, action, obj):
|
||||||
if not action.allowed:
|
if not action.allowed:
|
||||||
return False
|
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):
|
if not self.checkRoles(action.roles, obj):
|
||||||
return False
|
return False
|
||||||
if not self.checkPermission(action.permission, obj):
|
if not self.checkPermission(action.permission, obj):
|
||||||
return False
|
return False
|
||||||
return True
|
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):
|
def checkRoles(self, roles, obj):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,12 @@ class IAction(Interface):
|
||||||
'to execute this action; no check when empty.')
|
'to execute this action; no check when empty.')
|
||||||
permission = Attribute('The name of a permission that is needed for '
|
permission = Attribute('The name of a permission that is needed for '
|
||||||
'executing this action; no check when empty.')
|
'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) '
|
schema = Attribute('An optional schema (a sequence of field specifications) '
|
||||||
'that provides information on fields to be shown in a '
|
'that provides information on fields to be shown in a '
|
||||||
'form used for executing the action.')
|
'form used for executing the action.')
|
||||||
|
@ -97,6 +103,17 @@ class IStateful(Interface):
|
||||||
for the current state.
|
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.')
|
request = Attribute('Optional publication request.')
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue