[CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.10.2.1 ActionProviderBase.py:1.13.6.1 ActionsTool.py:1.31.2.1
Chris McDonough
chrism@zope.com
Wed, 31 Jul 2002 01:32:20 -0400
Update of /cvs-repository/CMF/CMFCore
In directory cvs.zope.org:/tmp/cvs-serv11157
Modified Files:
Tag: chrism-actions-branch
ActionInformation.py ActionProviderBase.py ActionsTool.py
Log Message:
Modified actions handling:
- Actions tool no longer swallows action dictionary elements it doesn't
understand.
- listFilteredActionsFor refactored.
- ActionInformation objects grew some new methods as utilities.
This is on a branch for now until Tres has a chance to look at it,
as it's a somewhat big patch.
=== CMF/CMFCore/ActionInformation.py 1.10 => 1.10.2.1 ===
from CMFCorePermissions import ManagePortal
from utils import _dtmldir
from utils import getToolByName
+from types import StringType
class ActionInformation( SimpleItem ):
@@ -38,57 +39,36 @@
__allow_access_to_unprotected_subobjects__ = 1
security = ClassSecurityInfo()
+ _action_info = None
- def __init__( self
- , id
- , title=''
- , description=''
- , category='object'
- , condition=''
- , permissions=()
- , priority=10
- , visible=1
- , action=''
- ):
+ def __init__( self, id, **kw):
""" Set up an instance.
"""
- if condition and type( condition ) == type( '' ):
- condition = Expression( condition )
-
- if action and type( action ) == type( '' ):
- action = Expression( action )
-
- self.id = id
- self.title = title
- self.description = description
- self.category = category
- self.condition = condition
- self.permissions = permissions
- self.priority = priority
- self.visible = visible
- self.action = action
+ kw['id'] = id
+ self.updateActionInfoDict(kw)
security.declareProtected( View, 'Title' )
def Title(self):
""" Return the Action title.
"""
- return self.title or self.getId()
+ return self._action_info['title'] or self.getId()
security.declareProtected( View, 'Description' )
def Description( self ):
""" Return a description of the action.
"""
- return self.description
+ return self._action_info['description']
security.declarePrivate( 'testCondition' )
def testCondition( self, ec ):
""" Evaluate condition using context, 'ec', and return 0 or 1.
"""
- if self.condition:
- return self.condition(ec)
+ cond = self._action_info['condition']
+ if cond:
+ return cond(ec)
else:
return 1
@@ -99,6 +79,7 @@
info about the action.
"""
info = {}
+ info.update(self._action_info)
info['id'] = self.id
info['name'] = self.Title()
action_obj = self._getActionObject()
@@ -106,22 +87,14 @@
info['permissions'] = self.getPermissions()
info['category'] = self.getCategory()
info['visible'] = self.getVisibility()
- return info
+ return info
security.declarePrivate( '_getActionObject' )
def _getActionObject( self ):
""" Find the action object, working around name changes.
"""
- action = getattr( self, 'action', None )
-
- if action is None: # Forward compatibility, used to be '_action'
- action = getattr( self, '_action', None )
- if action is not None:
- self.action = self._action
- del self._action
-
- return action
+ return self._action_info.get('action', None )
security.declarePublic( 'getActionExpression' )
def getActionExpression( self ):
@@ -136,7 +109,10 @@
""" Return the text of the TALES expression for our condition.
"""
- return getattr( self, 'condition', None ) and self.condition.text or ''
+ cond = self._action_info['condition']
+ if hasattr(cond, 'text'):
+ return cond.text
+ return ''
security.declarePublic( 'getPermission' )
def getPermissions( self ):
@@ -145,37 +121,73 @@
Return an empty tuple if no permission is required.
"""
- return self.permissions
+ return self._action_info['permissions']
security.declarePublic( 'getCategory' )
def getCategory( self ):
""" Return the category in which the action should be grouped.
"""
- return self.category or 'object'
+ return self._action_info.get('category') or 'object'
security.declarePublic( 'getVisibility' )
def getVisibility( self ):
""" Return whether the action should be visible in the CMF UI.
"""
- return self.visible
+ return self._action_info['visible']
security.declarePrivate( 'clone' )
def clone( self ):
""" Return a newly-created AI just like us.
"""
- return self.__class__( id=self.id
- , title=self.title
- , description=self.description
- , category =self.category
- , condition=self.getCondition()
- , permissions=self.permissions
- , priority =self.priority
- , visible=self.visible
- , action=self.getActionExpression()
- )
+ kw = self._action_info.copy()
+ id = kw['id']
+ del kw['id']
+ return apply(self.__class__, (id,), kw)
+
+ security.declarePrivate('getActionInfo')
+ def getActionInfoDict( self ):
+ return self._action_info.copy()
+
+ security.declarePrivate('updateActionInfo')
+ def updateActionInfoDict( self, kw ):
+ if self._action_info is None:
+ self._action_info = {}
+ kw['id'] = kw.get('id', getattr(self, 'id'))
+ kw['title'] = kw.get('title', '')
+ kw['description'] = kw.get('description', '')
+ kw['category'] = kw.get('category', 'object')
+ kw['condition'] = kw.get('condition', '')
+ kw['permissions'] = kw.get('permissions', ())
+ kw['priority'] = kw.get('priority', 10)
+ kw['visible'] = kw.get('visible', 1)
+ kw['action'] = kw.get('action', '')
+ condition = kw['condition'] = kw.get('condition', '')
+ if condition and isinstance(condition, StringType):
+ condition = kw['condition'] = Expression( condition )
+
+ action = kw['action'] = kw.get('action', '')
+ if action and isinstance(action, StringType):
+ action = kw['action'] = Expression( action )
+ self._action_info.update(kw)
+ self.id = kw['id']
+
+ security.declarePublic('query')
+ def query(self, name, default=None):
+ """ returns the item named by name in _action_info_dict or default """
+ return self._action_info.get(name, default)
+
+ def __setstate__(self, state):
+ if not state.has_key('_action_info'):
+ kw = {}
+ for name in ('id', 'title', 'description', 'category', 'condition',
+ 'permissions', 'priority', 'visible', 'action'):
+ kw[name] = state.get(name)
+ del state[name]
+ self._action_info = kw
+ self.__dict__.update(state)
InitializeClass( ActionInformation )
=== CMF/CMFCore/ActionProviderBase.py 1.13 => 1.13.6.1 ===
for a in self.listActions():
- a1 = {}
+ a1 = a.getActionInfoDict()
a1['id'] = a.getId()
a1['name'] = a.Title()
p = a.getPermissions()
@@ -138,7 +138,10 @@
actions = []
for index in range( len( self._actions ) ):
- actions.append( self._extractAction( properties, index ) )
+ action = self._actions[index].clone()
+ new_action = self._extractAction( properties, index )
+ action.updateActionInfoDict(new_action.getActionInfoDict())
+ actions.append( action )
self._actions = tuple( actions )
=== CMF/CMFCore/ActionsTool.py 1.31 => 1.31.2.1 ===
from ActionInformation import ActionInformation, oai
from ActionProviderBase import ActionProviderBase
from TypesTool import TypeInformation
+from types import DictionaryType
class ActionsTool(UniqueObject, OFS.Folder.Folder, ActionProviderBase):
"""
@@ -159,119 +160,126 @@
# 'portal_actions' interface methods
#
- def _listActions(self,append,object,info,ec):
- a = object.listActions(info)
- if a and type(a[0]) is not type({}):
- for ai in a:
- if ai.testCondition(ec):
- append(ai.getAction(ec))
- else:
- for i in a:
- append(i)
+ security.declarePrivate('getProviderActions')
+ def getProviderActions(self, info=None):
+ # Return actions from specific tools.
+ l = []
+ for provider_name in self.listActionProviders():
+ provider = getattr(self, provider_name)
+ actions = provider.listActions(info)
+ l.extend(actions)
+ return l
+
+ security.declarePrivate('getTypeActions')
+ def getTypeActions(self, object, info=None):
+ # Return actions from object.
+ if object is None:
+ return []
+ l = []
+ types_tool = getToolByName( self, 'portal_types' )
+ # we might get None back from getTypeInfo. We construct
+ # a dummy TypeInformation object here in that case (the 'or'
+ # case). This prevents us from needing to check the condition.
+ ti = types_tool.getTypeInfo( object ) or TypeInformation('Dummy')
+ defs = ti.getActions()
+ url = object_url = object.absolute_url()
+ for d in defs:
+ # we can't modify or expose the original actionsd... this
+ # stems from the fact that getActions returns a ref to the
+ # actual dictionary used to store actions instead of a
+ # copy. We copy it here to prevent it from being modified.
+ d = d.copy()
+ d['id'] = d.get('id', None)
+ if d['action']:
+ url = '%s/%s' % (object_url, d['action'])
+ d['url'] = url
+ d['category'] = d.get('category', 'object')
+ d['visible'] = d.get('visible', 1)
+ l.append(d)
+
+ if hasattr(aq_base(object), 'listActions'):
+ l.extend(object.listActions())
+
+ return l
+
+ def _findParentFolder(self, object):
+ # Search up the object's containment hierarchy until we find an
+ # object that claims it's a folder.
+ context = object
+ while not hasattr(aq_base(context), 'isPrincipiaFolderish'):
+ new_context = aq_parent(aq_inner(context))
+ if context is new_context:
+ break
+ context = new_context
+ return context
+
security.declarePublic('listFilteredActionsFor')
def listFilteredActionsFor(self, object=None):
'''Gets all actions available to the user and returns a mapping
containing user actions, object actions, and global actions.
'''
- portal = aq_parent(aq_inner(self))
- if object is None or not hasattr(object, 'aq_base'):
- folder = portal
- else:
- folder = object
- # Search up the containment hierarchy until we find an
- # object that claims it's a folder.
- while folder is not None:
- if getattr(aq_base(folder), 'isPrincipiaFolderish', 0):
- # found it.
- break
- else:
- folder = aq_parent(aq_inner(folder))
- ec = createExprContext(folder, portal, object)
actions = []
- append = actions.append
- info = oai(self, folder, object)
- # Include actions from specific tools.
- for provider_name in self.listActionProviders():
- provider = getattr(self, provider_name)
- self._listActions(append,provider,info,ec)
+ portal = folder = aq_parent(aq_inner(self))
- # Include actions from object.
- if object is not None:
- base = aq_base(object)
- types_tool = getToolByName( self, 'portal_types' )
- # we might get None back from getTypeInfo. We construct
- # a dummy TypeInformation object here in that case (the 'or'
- # case). This prevents us from needing to check the condition.
- ti = types_tool.getTypeInfo( object ) or TypeInformation('Dummy')
- defs = ti.getActions()
- url = object_url = object.absolute_url()
- for d in defs:
- # we can't modify or expose the original actionsd... this
- # stems from the fact that getActions returns a ref to the
- # actual dictionary used to store actions instead of a
- # copy. We copy it here to prevent it from being modified.
- d = d.copy()
- d['id'] = d.get('id', None)
- if d['action']:
- url = '%s/%s' % (object_url, d['action'])
- d['url'] = url
- d['category'] = d.get('category', 'object')
- d['visible'] = d.get('visible', 1)
- actions.append(d)
-
- if hasattr(base, 'listActions'):
- self._listActions(append,object,info,ec)
-
- # Reorganize the actions by category,
- # filtering out disallowed actions.
- filtered_actions={'user':[],
- 'folder':[],
- 'object':[],
- 'global':[],
- 'workflow':[],
+ if object is not None and hasattr(object, 'aq_base'):
+ folder = self._findParentFolder(object)
+
+ # include actions from action providers
+ actions.extend(self.getProviderActions(oai(self, folder, object)))
+
+ # include actions from types tool
+ actions.extend(self.getTypeActions(object))
+
+ # Reorganize the actions by category, filtering out disallowed actions.
+ filtered_actions={
+ 'user':[], 'folder':[], 'object':[], 'global':[], 'workflow':[],
}
+ expr_context = createExprContext(folder, portal, object)
for action in actions:
- category = action['category']
- permissions = action.get('permissions', None)
- visible = action.get('visible', 1)
- if not visible:
+ action, category = organizeAction(
+ action, portal, folder, object, expr_context
+ )
+ if None in (action, category):
continue
- verified = 0
- if not permissions:
- # This action requires no extra permissions.
- verified = 1
- else:
- if (object is not None and
- (category.startswith('object') or
- category.startswith('workflow'))):
- context = object
- elif (folder is not None and
- category.startswith('folder')):
- context = folder
- else:
- context = portal
- for permission in permissions:
- # The user must be able to match at least one of
- # the listed permissions.
- if _checkPermission(permission, context):
- verified = 1
- break
- if verified:
- catlist = filtered_actions.get(category, None)
- if catlist is None:
- filtered_actions[category] = catlist = []
- # Filter out duplicate actions by identity...
- if not action in catlist:
- catlist.append(action)
- # ...should you need it, here's some code that filters
- # by equality (use instead of the two lines above)
- #if not [a for a in catlist if a==action]:
- # catlist.append(action)
+ catlist = filtered_actions.setdefault(category, [])
+ if not action in catlist:
+ # no dupes
+ catlist.append(action)
+
return filtered_actions
- # listFilteredActions() is an alias.
+ # listFilteredActions is an alias for listFilteredActionsFor.
security.declarePublic('listFilteredActions')
listFilteredActions = listFilteredActionsFor
+
+def organizeAction(action, portal, folder, object, expr_context):
+ """ Organize the action into a category and expand the action
+ into a dictionary if it is an ActionInformation object """
+ if not isinstance(action, DictionaryType):
+ # this is an ActionInformation object
+ if not action.testCondition(expr_context):
+ # it did not pass the condition
+ return None, None
+ action = action.getAction(expr_context)
+
+ if action.get('visible', 1):
+ category = action.get('category', 'object')
+ permissions = action.get('permissions', None)
+ # context will be one of object, folder, or portal
+ context = ((category in ('object', 'workflow') and object) or
+ (category == 'folder' and folder)) or portal
+ if permissions and not checkPermissions(permissions, context):
+ # inadequate permissions to see the action
+ return None, None
+
+ return action, category
+
+def checkPermissions(permissions, context):
+ for permission in permissions:
+ # The user must be able to match at least one of
+ # the listed permissions.
+ if _checkPermission(permission, context):
+ return 1
InitializeClass(ActionsTool)