provide 'actors' and 'condition' attributes for more control on actions/transitions
This commit is contained in:
		
							parent
							
								
									e6df09d4dc
								
							
						
					
					
						commit
						68ed9d878b
					
				
					 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' | ||||||
|  | 
 | ||||||
|  |  | ||||||
|  | @ -82,6 +82,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 | ||||||
|  | @ -123,12 +123,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