[CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.18
ActionProviderBase.py:1.21 ActionsTool.py:1.42
DiscussionTool.py:1.14 Expression.py:1.6 TypesTool.py:1.63
WorkflowTool.py:1.42
Yvo Schubbe
cvs-admin at zope.org
Thu Nov 27 10:07:20 EST 2003
Update of /cvs-repository/CMF/CMFCore
In directory cvs.zope.org:/tmp/cvs-serv3099/CMFCore
Modified Files:
ActionInformation.py ActionProviderBase.py ActionsTool.py
DiscussionTool.py Expression.py TypesTool.py WorkflowTool.py
Log Message:
Merged yuppie-listActionInfos-branch:
- refactored listFilteredActionsFor()
- added listActionInfos() and getActionInfo() to Action providers
- added helper methods getOAI() and getExprContext()
=== CMF/CMFCore/ActionInformation.py 1.17 => 1.18 ===
--- CMF/CMFCore/ActionInformation.py:1.17 Mon Sep 1 11:18:34 2003
+++ CMF/CMFCore/ActionInformation.py Thu Nov 27 10:06:49 2003
@@ -15,20 +15,22 @@
$Id$
"""
+from types import StringType
+
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass
-from Acquisition import aq_inner, aq_parent
+from Acquisition import aq_base, aq_inner, aq_parent
from OFS.SimpleItem import SimpleItem
from Expression import Expression
from CMFCorePermissions import View
from utils import getToolByName
-from types import StringType
+
class ActionInformation( SimpleItem ):
""" Represent a single selectable action.
-
+
Actions generate links to views of content, or to specific methods
of the site. They can be filtered via their conditions.
"""
@@ -59,10 +61,10 @@
self.id = id
self.title = title
self.description = description
- self.category = category
+ self.category = category
self.condition = condition
self.permissions = permissions
- self.priority = priority
+ self.priority = priority
self.visible = visible
self.setActionExpression(action)
@@ -106,7 +108,7 @@
info['permissions'] = self.getPermissions()
info['category'] = self.getCategory()
info['visible'] = self.getVisibility()
- return info
+ return info
security.declarePrivate( '_getActionObject' )
def _getActionObject( self ):
@@ -192,6 +194,35 @@
InitializeClass( ActionInformation )
+
+def getOAI(context, object=None):
+ request = getattr(context, 'REQUEST', None)
+ if request:
+ cache = request.get('_oai_cache', None)
+ if cache is None:
+ request['_oai_cache'] = cache = {}
+ info = cache.get( str(object), None )
+ else:
+ info = None
+ if info is None:
+ if object is None or not hasattr(object, 'aq_base'):
+ folder = None
+ 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))
+ info = oai(context, folder, object)
+ if request:
+ cache[ str(object) ] = info
+ return info
+
+
class oai:
#Provided for backwards compatability
# Provides information that may be needed when constructing the list of
@@ -223,4 +254,3 @@
if hasattr(self, name):
return getattr(self, name)
raise KeyError, name
-
=== CMF/CMFCore/ActionProviderBase.py 1.20 => 1.21 ===
--- CMF/CMFCore/ActionProviderBase.py:1.20 Sat Oct 18 04:33:53 2003
+++ CMF/CMFCore/ActionProviderBase.py Thu Nov 27 10:06:49 2003
@@ -15,15 +15,22 @@
$Id$
"""
+from types import StringType
+
from Globals import DTMLFile, InitializeClass
from AccessControl import ClassSecurityInfo
from ActionInformation import ActionInformation
+from ActionInformation import getOAI
from CMFCorePermissions import ManagePortal
from Expression import Expression
-from utils import _dtmldir
-
+from Expression import getExprContext
from interfaces.portal_actions import ActionProvider as IActionProvider
+from interfaces.portal_actions \
+ import OldstyleActionProvider as IOldstyleActionProvider
+from utils import _checkPermission
+from utils import _dtmldir
+from utils import getToolByName
class ActionProviderBase:
@@ -47,12 +54,74 @@
#
# ActionProvider interface
#
- security.declarePrivate( 'listActions' )
- def listActions( self, info=None ):
- """ Return all the actions defined by a provider.
+ security.declarePrivate('listActions')
+ def listActions(self, info=None, object=None):
+ """ List all the actions defined by a provider.
"""
return self._actions or ()
+ security.declarePublic('listActionInfos')
+ def listActionInfos(self, action_chain=None, object=None,
+ check_visibility=1, check_permissions=1,
+ check_condition=1, max=-1):
+ # List Action info mappings.
+ # (method is without docstring to disable publishing)
+ #
+ ec = getExprContext(self, object)
+ actions = self.listActions(object=object)
+
+ if action_chain:
+ filtered_actions = []
+ if isinstance(action_chain, StringType):
+ action_chain = (action_chain,)
+ for action_ident in action_chain:
+ sep = action_ident.rfind('/')
+ category, id = action_ident[:sep], action_ident[sep+1:]
+ for ai in actions:
+ if id == ai.getId() and category == ai.getCategory():
+ filtered_actions.append(ai)
+ actions = filtered_actions
+
+ action_infos = []
+ for ai in actions:
+ if check_visibility and not ai.getVisibility():
+ continue
+ if check_permissions:
+ permissions = ai.getPermissions()
+ if permissions:
+ category = ai.getCategory()
+ if (object is not None and
+ (category.startswith('object') or
+ category.startswith('workflow'))):
+ context = object
+ elif (ec.contexts['folder'] is not None and
+ category.startswith('folder')):
+ context = ec.contexts['folder']
+ else:
+ context = ec.contexts['portal']
+ for permission in permissions:
+ allowed = _checkPermission(permission, context)
+ if allowed:
+ break
+ if not allowed:
+ continue
+ if check_condition and not ai.testCondition(ec):
+ continue
+ action_infos.append( ai.getAction(ec) )
+ if max + 1 and len(action_infos) >= max:
+ break
+ return action_infos
+
+ security.declarePublic('getActionInfo')
+ def getActionInfo(self, action_chain, object=None, check_visibility=0,
+ check_condition=0):
+ """ Get an Action info mapping specified by a chain of actions.
+ """
+ action_infos = self.listActionInfos(action_chain, object,
+ check_visibility=check_visibility,
+ check_condition=check_condition, max=1)
+ return action_infos and action_infos[0] or None
+
#
# ZMI methods
#
@@ -278,3 +347,83 @@
)
InitializeClass(ActionProviderBase)
+
+
+class OldstyleActionProviderBase:
+ """ Base class for ActionProviders with oldstyle Actions.
+ """
+
+ __implements__ = IOldstyleActionProvider
+
+ security = ClassSecurityInfo()
+
+ _actions = ()
+
+ #
+ # OldstyleActionProvider interface
+ #
+ security.declarePrivate('listActions')
+ def listActions(self, info):
+ """ List all the actions defined by a provider.
+ """
+ return self._actions or ()
+
+ security.declarePublic('listActionInfos')
+ def listActionInfos(self, action_chain=None, object=None,
+ check_visibility=1, check_permissions=1,
+ check_condition=1, max=-1):
+ # List Action info mappings.
+ # (method is without docstring to disable publishing)
+ #
+ info = getOAI(self, object)
+ actions = self.listActions(info=info)
+
+ if action_chain:
+ filtered_actions = []
+ if isinstance(action_chain, StringType):
+ action_chain = (action_chain,)
+ for action_ident in action_chain:
+ sep = action_ident.rfind('/')
+ category, id = action_ident[:sep], action_ident[sep+1:]
+ for ai in actions:
+ if id == ai['id'] and category == ai['category']:
+ filtered_actions.append(ai)
+ actions = filtered_actions
+
+ action_infos = []
+ for ai in actions:
+ if check_permissions:
+ permissions = ai.get( 'permissions', () )
+ if permissions:
+ category = ai['category']
+ if (object is not None and
+ (category.startswith('object') or
+ category.startswith('workflow'))):
+ context = object
+ elif (info['folder'] is not None and
+ category.startswith('folder')):
+ context = info['folder']
+ else:
+ context = info['portal']
+ for permission in permissions:
+ allowed = _checkPermission(permission, context)
+ if allowed:
+ break
+ if not allowed:
+ continue
+ action_infos.append(ai)
+ if max + 1 and len(action_infos) >= max:
+ break
+ return action_infos
+
+ security.declarePublic('getActionInfo')
+ def getActionInfo(self, action_chain, object=None, check_visibility=0,
+ check_condition=0):
+ """ Get an Action info mapping specified by a chain of actions.
+ """
+ action_infos = self.listActionInfos(action_chain, object,
+ check_visibility=check_visibility,
+ check_condition=check_condition, max=1)
+ return action_infos and action_infos[0] or None
+
+InitializeClass(OldstyleActionProviderBase)
=== CMF/CMFCore/ActionsTool.py 1.41 => 1.42 ===
--- CMF/CMFCore/ActionsTool.py:1.41 Fri Nov 14 03:34:55 2003
+++ CMF/CMFCore/ActionsTool.py Thu Nov 27 10:06:49 2003
@@ -15,26 +15,29 @@
$Id$
"""
+from types import DictionaryType
+
from Globals import InitializeClass, DTMLFile, package_home
-from Acquisition import aq_base, aq_inner, aq_parent
from AccessControl import ClassSecurityInfo
+from Acquisition import aq_base, aq_inner, aq_parent
from OFS.Folder import Folder
from OFS.SimpleItem import SimpleItem
-from Expression import Expression, createExprContext
-from ActionInformation import ActionInformation, oai
+from ActionInformation import ActionInformation
+from ActionInformation import getOAI
from ActionProviderBase import ActionProviderBase
-from TypesTool import TypeInformation
from CMFCorePermissions import ListFolderContents
from CMFCorePermissions import ManagePortal
+from Expression import Expression
+from Expression import getExprContext
+from interfaces.portal_actions import portal_actions as IActionsTool
+from TypesTool import TypeInformation
from utils import _checkPermission
from utils import _dtmldir
from utils import getToolByName
from utils import SimpleItemWithProperties
from utils import UniqueObject
-from interfaces.portal_actions import portal_actions as IActionsTool
-
class ActionsTool(UniqueObject, Folder, ActionProviderBase):
"""
@@ -51,7 +54,7 @@
, action=Expression(
text='string: ${folder_url}/folder_contents')
, condition=Expression(
- text='python: folder is not object')
+ text='python: folder is not object')
, permissions=(ListFolderContents,)
, category='object'
, visible=1
@@ -89,7 +92,7 @@
, 'action' : 'manage_overview'
}
) + Folder.manage_options
- )
+ )
#
# ZMI methods
@@ -156,37 +159,25 @@
def listFilteredActionsFor(self, object=None):
""" List all actions available to the user.
"""
- 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)
+ if hasattr( aq_base(provider), 'listActionInfos' ):
+ actions.extend( provider.listActionInfos(object=object) )
+ else:
+ # for Action Providers written for CMF versions before 1.5
+ actions.extend( self._listActionInfos(provider, object) )
+ # for objects written for CMF versions before 1.5
# Include actions from object.
if object is not None:
base = aq_base(object)
if hasattr(base, 'listActions'):
- self._listActions(append,object,info,ec)
+ actions.extend( self._listActionInfos(object, object) )
- # Reorganize the actions by category,
- # filtering out disallowed actions.
+ # Reorganize the actions by category.
filtered_actions={'user':[],
'folder':[],
'object':[],
@@ -195,44 +186,16 @@
}
for action in actions:
category = action['category']
- permissions = action.get('permissions', None)
- visible = action.get('visible', 1)
- if not visible:
- continue
- verified = 0
- if not permissions:
- # This action requires no extra permissions.
- verified = 1
- else:
- # startswith() is used so that we can have several
- # different categories that are checked in the object or
- # folder context.
- 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.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)
return filtered_actions
# listFilteredActions() is an alias.
@@ -240,16 +203,65 @@
listFilteredActions = listFilteredActionsFor
#
- # Helper methods
+ # Helper method for backwards compatibility
#
- 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))
+ def _listActionInfos(self, provider, object):
+ """ for Action Providers written for CMF versions before 1.5
+ """
+ info = getOAI(self, object)
+ actions = provider.listActions(info)
+
+ action_infos = []
+ if actions and type(actions[0]) is not DictionaryType:
+ ec = getExprContext(self, object)
+ for ai in actions:
+ if not ai.getVisibility():
+ continue
+ permissions = ai.getPermissions()
+ if permissions:
+ category = ai.getCategory()
+ if (object is not None and
+ (category.startswith('object') or
+ category.startswith('workflow'))):
+ context = object
+ elif (info['folder'] is not None and
+ category.startswith('folder')):
+ context = info['folder']
+ else:
+ context = info['portal']
+ for permission in permissions:
+ allowed = _checkPermission(permission, context)
+ if allowed:
+ break
+ if not allowed:
+ continue
+ if not ai.testCondition(ec):
+ continue
+ action_infos.append( ai.getAction(ec) )
else:
- for i in a:
- append(i)
+ for i in actions:
+ if not i.get('visible', 1):
+ continue
+ permissions = i.get('permissions', None)
+ if permissions:
+ category = i['category']
+ if (object is not None and
+ (category.startswith('object') or
+ category.startswith('workflow'))):
+ context = object
+ elif (info['folder'] is not None and
+ category.startswith('folder')):
+ context = info['folder']
+ else:
+ context = info['portal']
+
+ for permission in permissions:
+ allowed = _checkPermission(permission, context)
+ if allowed:
+ break
+ if not allowed:
+ continue
+ action_infos.append(i)
+ return action_infos
InitializeClass(ActionsTool)
=== CMF/CMFCore/DiscussionTool.py 1.13 => 1.14 ===
--- CMF/CMFCore/DiscussionTool.py:1.13 Fri Nov 14 03:34:55 2003
+++ CMF/CMFCore/DiscussionTool.py Thu Nov 27 10:06:49 2003
@@ -20,13 +20,12 @@
from Acquisition import Implicit
from AccessControl import ClassSecurityInfo
+from ActionProviderBase import OldstyleActionProviderBase
from CMFCorePermissions import AccessContentsInformation
from CMFCorePermissions import ManagePortal
from CMFCorePermissions import ReplyToItem
from CMFCorePermissions import View
from interfaces.Discussions import OldDiscussable as IOldDiscussable
-from interfaces.portal_actions \
- import OldstyleActionProvider as IOldstyleActionProvider
from interfaces.portal_discussion \
import oldstyle_portal_discussion as IOldstyleDiscussionTool
from utils import _dtmldir
@@ -113,9 +112,10 @@
return ""
-class DiscussionTool (UniqueObject, SimpleItem):
+class DiscussionTool (UniqueObject, SimpleItem, OldstyleActionProviderBase):
- __implements__ = (IOldstyleDiscussionTool, IOldstyleActionProvider)
+ __implements__ = (IOldstyleDiscussionTool,
+ OldstyleActionProviderBase.__implements__)
id = 'portal_discussion'
meta_type = 'Oldstyle CMF Discussion Tool'
=== CMF/CMFCore/Expression.py 1.5 => 1.6 ===
--- CMF/CMFCore/Expression.py:1.5 Thu Aug 1 15:05:11 2002
+++ CMF/CMFCore/Expression.py Thu Nov 27 10:06:49 2003
@@ -1,14 +1,14 @@
##############################################################################
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
-#
+#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
-#
+#
##############################################################################
""" Expressions in a web-configurable workflow.
@@ -17,7 +17,7 @@
import Globals
from Globals import Persistent
-from Acquisition import aq_inner, aq_parent
+from Acquisition import aq_base, aq_inner, aq_parent
from AccessControl import getSecurityManager, ClassSecurityInfo
from utils import getToolByName
@@ -25,6 +25,7 @@
from Products.PageTemplates.TALES import SafeMapping
from Products.PageTemplates.Expressions import SecureModuleImporter
+
class Expression (Persistent):
text = ''
_v_compiled = None
@@ -48,6 +49,36 @@
return res
Globals.InitializeClass(Expression)
+
+
+def getExprContext(context, object=None):
+ request = getattr(context, 'REQUEST', None)
+ if request:
+ cache = request.get('_ec_cache', None)
+ if cache is None:
+ request['_ec_cache'] = cache = {}
+ ec = cache.get( str(object), None )
+ else:
+ ec = None
+ if ec is None:
+ utool = getToolByName(context, 'portal_url')
+ portal = utool.getPortalObject()
+ 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)
+ if request:
+ cache[ str(object) ] = ec
+ return ec
def createExprContext(folder, portal, object):
=== CMF/CMFCore/TypesTool.py 1.62 => 1.63 ===
--- CMF/CMFCore/TypesTool.py:1.62 Fri Nov 14 03:34:55 2003
+++ CMF/CMFCore/TypesTool.py Thu Nov 27 10:06:49 2003
@@ -252,8 +252,7 @@
return self.global_allow
security.declarePublic('listActions')
- def listActions( self, info=None ):
-
+ def listActions(self, info=None, object=None):
""" Return a sequence of the action info objects for this type.
"""
if self._actions and type( self._actions[0] ) == type( {} ):
@@ -888,16 +887,15 @@
RESPONSE.redirect( immediate_url )
security.declarePrivate( 'listActions' )
- def listActions( self, info=None ):
- """
- List type-related actions.
+ def listActions(self, info=None, object=None):
+ """ List all the actions defined by a provider.
"""
actions = list( self._actions )
- if info is not None:
-
- type_info = self.getTypeInfo( info.content )
-
+ if object is None and info is not None:
+ object = info.content
+ if object is not None:
+ type_info = self.getTypeInfo(object)
if type_info is not None:
actions.extend( type_info.listActions() )
=== CMF/CMFCore/WorkflowTool.py 1.41 => 1.42 ===
--- CMF/CMFCore/WorkflowTool.py:1.41 Fri Nov 14 03:34:55 2003
+++ CMF/CMFCore/WorkflowTool.py Thu Nov 27 10:06:49 2003
@@ -22,9 +22,8 @@
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base, aq_inner, aq_parent
+from ActionProviderBase import OldstyleActionProviderBase
from CMFCorePermissions import ManagePortal
-from interfaces.portal_actions \
- import OldstyleActionProvider as IOldstyleActionProvider
from interfaces.portal_workflow import portal_workflow as IWorkflowTool
from utils import _dtmldir
from utils import getToolByName
@@ -53,13 +52,13 @@
raise KeyError, name
-class WorkflowTool (UniqueObject, Folder):
-
+class WorkflowTool(UniqueObject, Folder, OldstyleActionProviderBase):
""" Mediator tool, mapping workflow objects
"""
id = 'portal_workflow'
meta_type = 'CMF Workflow Tool'
- __implements__ = (IWorkflowTool, IOldstyleActionProvider)
+ __implements__ = (IWorkflowTool,
+ OldstyleActionProviderBase.__implements__)
_chains_by_type = None # PersistentMapping
_default_chain = ('default_workflow',)
@@ -344,7 +343,7 @@
'Requested workflow definition not found.')
else:
return default
- res = apply(wf.getInfoFor, (ob, name, default) + args, kw)
+ res = wf.getInfoFor(ob, name, default, *args, **kw)
if res is _marker:
raise WorkflowException('Could not get info: %s' % name)
return res
@@ -590,7 +589,7 @@
wfs = ()
if wf is None:
# No workflow wraps this method.
- return apply(func, args, kw)
+ return func(*args, **kw)
return self._invokeWithNotification(
wfs, ob, method_id, wf.wrapWorkflowMethod,
(ob, method_id, func, args, kw), {})
@@ -619,7 +618,7 @@
for w in wfs:
w.notifyBefore(ob, action)
try:
- res = apply(func, args, kw)
+ res = func(*args, **kw)
except ObjectDeleted, ex:
res = ex.getResult()
reindex = 0
More information about the CMF-checkins
mailing list