[CMF-checkins] CVS: Products/CMFCore - ActionInformation.py:1.24 ActionProviderBase.py:1.29 ActionsTool.py:1.50 DiscussionTool.py:1.16 WorkflowTool.py:1.45

Yvo Schubbe y.2004_ at wcm-solutions.de
Mon Jul 26 06:13:44 EDT 2004


Update of /cvs-repository/Products/CMFCore
In directory cvs.zope.org:/tmp/cvs-serv8720/CMFCore

Modified Files:
	ActionInformation.py ActionProviderBase.py ActionsTool.py 
	DiscussionTool.py WorkflowTool.py 
Log Message:
- merged yuppie-apb-redo-branch:

      o Removed again OldstyleActionProvider Interface and
        OldstyleActionProviderBase that existed only in 1.5.0-alpha.
        ActionProvider now also works with oldstyle Action mappings.

      o listActionInfos() and getActionInfo() now return ActionInfo objects
        instead of Action info mappings. ActionInfo objects have a backwards
        compatible mapping interface.

(hope there are no issues with this checkin, I'll be AFK the next 4 days)


=== Products/CMFCore/ActionInformation.py 1.23 => 1.24 ===
--- Products/CMFCore/ActionInformation.py:1.23	Mon Jul 19 14:11:35 2004
+++ Products/CMFCore/ActionInformation.py	Mon Jul 26 06:13:13 2004
@@ -20,13 +20,97 @@
 from Globals import InitializeClass
 from OFS.SimpleItem import SimpleItem
 
+from interfaces.portal_actions import ActionInfo as IActionInfo
 from Expression import Expression
 from permissions import View
+from utils import _checkPermission
 from utils import getToolByName
 
 
 _unchanged = [] # marker
 
+class ActionInfo(dict):
+    """ A lazy dictionary for Action infos.
+    """
+    __implements__ = IActionInfo
+    __allow_access_to_unprotected_subobjects__ = 1
+
+    def __init__(self, action, ec):
+        self._marker = marker = object()
+
+        if isinstance(action, dict):
+            dict.__init__(self, action)
+            self.setdefault( 'id', self['name'].lower() )
+            self.setdefault( 'title', self['name'] )
+            self.setdefault( 'url', '' )
+            self.setdefault( 'permissions', () )
+            self.setdefault( 'category', 'object' )
+            self.setdefault( 'visible', True )
+            self['available'] = True
+            self['allowed'] = self['permissions'] and marker or True
+
+        else:
+            self._action = action
+            self._ec = ec
+            mapping = action.getMapping()
+            self['id']          = mapping['id']
+            self['title']       = mapping['title']
+            self['name']        = mapping['title']
+            self['url']         = mapping['action'] and marker or ''
+            self['permissions'] = mapping['permissions']
+            self['category']    = mapping['category']
+            self['visible']     = mapping['visible']
+            self['available']   = mapping['condition'] and marker or True
+            self['allowed']     = mapping['permissions'] and marker or True
+
+    def __getitem__(self, key):
+        value = dict.__getitem__(self, key)
+        if value == self._marker:
+            if key == 'allowed':
+                value = self[key] = self._checkPermissions()
+            elif key == 'available':
+                value = self[key] = self._checkCondition()
+            elif key == 'url':
+                value = self[key] = self._getURL()
+        return value
+
+    def __eq__(self, other):
+        # this is expensive, use it with care
+        [ self[key] for key in self ]
+        [ other[key] for key in other ]
+        return dict.__eq__(self, other)
+
+    def _getURL(self):
+        """ Get the result of the URL expression in the current context.
+        """
+        return self._action._getActionObject()(self._ec)
+
+    def _checkCondition(self):
+        """ Check condition expression in the current context.
+        """
+        return self._action.testCondition(self._ec)
+
+    def _checkPermissions(self):
+        """ Check permissions in the current context.
+        """
+        category = self['category']
+        object = self._ec.contexts['object']
+        if object is not None and ( category.startswith('object') or
+                                    category.startswith('workflow') ):
+            context = object
+        else:
+            folder = self._ec.contexts['folder']
+            if folder is not None and category.startswith('folder'):
+                context = folder
+            else:
+                context = self._ec.contexts['portal']
+
+        for permission in self['permissions']:
+            if _checkPermission(permission, context):
+                return True
+        return False
+
+
 class ActionInformation( SimpleItem ):
 
     """ Represent a single selectable action.
@@ -123,9 +207,9 @@
         """ Evaluate condition using context, 'ec', and return 0 or 1.
         """
         if self.condition:
-            return self.condition(ec)
+            return bool( self.condition(ec) )
         else:
-            return 1
+            return True
 
     security.declarePublic( 'getAction' )
     def getAction( self, ec ):
@@ -133,17 +217,7 @@
         """ Compute the action using context, 'ec'; return a mapping of
             info about the action.
         """
-        info = {}
-        info['id'] = self.id
-        info['title'] = info['name'] = self.Title()
-        expr = self.getActionExpression()
-        __traceback_info__ = (info['id'], info['name'], expr)
-        action_obj = self._getActionObject()
-        info['url'] = action_obj and action_obj( ec ) or ''
-        info['permissions'] = self.getPermissions()
-        info['category'] = self.getCategory()
-        info['visible'] = self.getVisibility()
-        return info
+        return ActionInfo(self, ec)
 
     security.declarePrivate( '_getActionObject' )
     def _getActionObject( self ):
@@ -168,7 +242,7 @@
         action = self._getActionObject()
         expr = action and action.text or ''
         if expr and isinstance(expr, basestring):
-            if not expr.startswith('python:') and not expr.startswith('string:'):
+            if not expr.startswith('string:') and not expr.startswith('python:'):
                 expr = 'string:${object_url}/%s' % expr
                 self.action = Expression( expr )
         return expr
@@ -176,7 +250,7 @@
     security.declarePrivate( 'setActionExpression' )
     def setActionExpression(self, action):
         if action and isinstance(action, basestring):
-            if not action.startswith('python:')  and not action.startswith('string:'):
+            if not action.startswith('string:') and not action.startswith('python:'):
                 action = 'string:${object_url}/%s' % action
                 action = Expression( action )
         self.action = action
@@ -215,13 +289,14 @@
     def getMapping(self):
         """ Get a mapping of this object's data.
         """
-        return { 'id': self.getId(),
-                 'title': self.Title(),
-                 'description': self.Description(),
-                 'category': self.getCategory(),
-                 'condition': self.getCondition(),
-                 'permissions': self.getPermissions(),
-                 'visible': self.getVisibility(),
+        return { 'id': self.id,
+                 'title': self.title or self.id,
+                 'description': self.description,
+                 'category': self.category or 'object',
+                 'condition': getattr(self, 'condition', None)
+                              and self.condition.text or '',
+                 'permissions': self.permissions,
+                 'visible': bool(self.visible),
                  'action': self.getActionExpression() }
 
     security.declarePrivate('clone')


=== Products/CMFCore/ActionProviderBase.py 1.28 => 1.29 ===
--- Products/CMFCore/ActionProviderBase.py:1.28	Mon Jul 19 14:11:35 2004
+++ Products/CMFCore/ActionProviderBase.py	Mon Jul 26 06:13:13 2004
@@ -19,15 +19,11 @@
 from Globals import DTMLFile
 from Globals import InitializeClass
 
+from ActionInformation import ActionInfo
 from ActionInformation import ActionInformation
-from ActionInformation import getOAI
-from Expression import Expression
 from Expression import getExprContext
 from interfaces.portal_actions import ActionProvider as IActionProvider
-from interfaces.portal_actions \
-        import OldstyleActionProvider as IOldstyleActionProvider
 from permissions import ManagePortal
-from utils import _checkPermission
 from utils import _dtmldir
 
 
@@ -80,11 +76,12 @@
     def listActionInfos(self, action_chain=None, object=None,
                         check_visibility=1, check_permissions=1,
                         check_condition=1, max=-1):
-        # List Action info mappings.
+        # List ActionInfo objects.
         # (method is without docstring to disable publishing)
         #
         ec = getExprContext(self, object)
         actions = self.listActions(object=object)
+        actions = [ ActionInfo(action, ec) for action in actions ]
 
         if action_chain:
             filtered_actions = []
@@ -94,36 +91,19 @@
                 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():
+                    if id == ai['id'] and category == ai['category']:
                         filtered_actions.append(ai)
             actions = filtered_actions
 
         action_infos = []
         for ai in actions:
-            if check_visibility and not ai.getVisibility():
+            if check_visibility and not ai['visible']:
+                continue
+            if check_permissions and not ai['allowed']:
                 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):
+            if check_condition and not ai['available']:
                 continue
-            action_infos.append( ai.getAction(ec) )
+            action_infos.append(ai)
             if max + 1 and len(action_infos) >= max:
                 break
         return action_infos
@@ -131,7 +111,7 @@
     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.
+        """ Get an ActionInfo object specified by a chain of actions.
         """
         action_infos = self.listActionInfos(action_chain, object,
                                        check_visibility=check_visibility,
@@ -176,8 +156,8 @@
         if not name:
             raise ValueError('A name is required.')
 
-        a_expr = action and Expression(text=str(action)) or ''
-        c_expr = condition and Expression(text=str(condition)) or ''
+        action = action and str(action) or ''
+        condition = condition and str(condition) or ''
 
         if not isinstance(permission, tuple):
             permission = (str(permission),)
@@ -186,11 +166,11 @@
 
         new_action = ActionInformation( id=str(id)
                                       , title=str(name)
-                                      , action=a_expr
-                                      , condition=c_expr
-                                      , permissions=permission
                                       , category=str(category)
-                                      , visible=int(visible)
+                                      , condition=condition
+                                      , permissions=permission
+                                      , visible=bool(visible)
+                                      , action=action
                                       )
 
         new_actions.append( new_action )
@@ -337,88 +317,3 @@
                                 )
 
 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.declarePrivate('getActionObject')
-    getActionObject = ActionProviderBase.getActionObject.im_func
-
-    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, basestring):
-                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)
-        if not action_infos:
-            raise ValueError('No Action meets the given specification.')
-        return action_infos[0]
-
-InitializeClass(OldstyleActionProviderBase)


=== Products/CMFCore/ActionsTool.py 1.49 => 1.50 ===
--- Products/CMFCore/ActionsTool.py:1.49	Tue Jul 13 12:49:39 2004
+++ Products/CMFCore/ActionsTool.py	Mon Jul 26 06:13:13 2004
@@ -28,6 +28,7 @@
 from ActionProviderBase import ActionProviderBase
 from Expression import Expression
 from Expression import getExprContext
+from interfaces.portal_actions import ActionProvider as IActionProvider
 from interfaces.portal_actions import portal_actions as IActionsTool
 from permissions import ListFolderContents
 from permissions import ManagePortal
@@ -153,7 +154,7 @@
         # Include actions from specific tools.
         for provider_name in self.listActionProviders():
             provider = getattr(self, provider_name)
-            if hasattr( aq_base(provider), 'listActionInfos' ):
+            if IActionProvider.isImplementedBy(provider):
                 actions.extend( provider.listActionInfos(object=object) )
             else:
                 # for Action Providers written for CMF versions before 1.5
@@ -162,7 +163,7 @@
         # Include actions from object.
         if object is not None:
             base = aq_base(object)
-            if hasattr(base, 'listActionInfos'):
+            if IActionProvider.isImplementedBy(base):
                 actions.extend( object.listActionInfos(object=object) )
             elif hasattr(base, 'listActions'):
                 # for objects written for CMF versions before 1.5
@@ -180,12 +181,10 @@
             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)
+            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]:
+            # by equality (use instead of the line above)
+            #if not action in catlist:
             #    catlist.append(action)
         return filtered_actions
 


=== Products/CMFCore/DiscussionTool.py 1.15 => 1.16 ===
--- Products/CMFCore/DiscussionTool.py:1.15	Thu Apr 29 12:13:16 2004
+++ Products/CMFCore/DiscussionTool.py	Mon Jul 26 06:13:13 2004
@@ -20,7 +20,7 @@
 from Acquisition import Implicit
 from AccessControl import ClassSecurityInfo
 
-from ActionProviderBase import OldstyleActionProviderBase
+from ActionProviderBase import ActionProviderBase
 from permissions import AccessContentsInformation
 from permissions import ManagePortal
 from permissions import ReplyToItem
@@ -112,10 +112,10 @@
         return ""
 
 
-class DiscussionTool (UniqueObject, SimpleItem, OldstyleActionProviderBase):
+class DiscussionTool (UniqueObject, SimpleItem, ActionProviderBase):
 
     __implements__ = (IOldstyleDiscussionTool,
-                      OldstyleActionProviderBase.__implements__)
+                      ActionProviderBase.__implements__)
 
     id = 'portal_discussion'
     meta_type = 'Oldstyle CMF Discussion Tool'
@@ -156,11 +156,13 @@
         return 0
 
     security.declarePrivate('listActions')
-    def listActions(self, info):
+    def listActions(self, info=None, object=None):
         # Return actions for reply and show replies
+        if object is not None or info is None:
+            info = getOAI(self, object)
         content = info.content
         if content is None or not self.isDiscussionAllowedFor(content):
-            return []
+            return ()
 
         discussion = self.getDiscussionFor(content)
         if discussion.aq_base == content.aq_base:


=== Products/CMFCore/WorkflowTool.py 1.44 => 1.45 ===
--- Products/CMFCore/WorkflowTool.py:1.44	Thu Apr 29 12:13:17 2004
+++ Products/CMFCore/WorkflowTool.py	Mon Jul 26 06:13:13 2004
@@ -22,7 +22,8 @@
 from AccessControl import ClassSecurityInfo
 from Acquisition import aq_base, aq_inner, aq_parent
 
-from ActionProviderBase import OldstyleActionProviderBase
+from ActionInformation import getOAI
+from ActionProviderBase import ActionProviderBase
 from permissions import ManagePortal
 from interfaces.portal_workflow import portal_workflow as IWorkflowTool
 from utils import _dtmldir
@@ -54,13 +55,13 @@
         raise KeyError, name
 
 
-class WorkflowTool(UniqueObject, Folder, OldstyleActionProviderBase):
+class WorkflowTool(UniqueObject, Folder, ActionProviderBase):
     """ Mediator tool, mapping workflow objects
     """
     id = 'portal_workflow'
     meta_type = 'CMF Workflow Tool'
     __implements__ = (IWorkflowTool,
-                      OldstyleActionProviderBase.__implements__)
+                      ActionProviderBase.__implements__)
 
     _chains_by_type = None  # PersistentMapping
     _default_chain = ('default_workflow',)
@@ -230,7 +231,7 @@
         return vars
 
     security.declarePrivate('listActions')
-    def listActions(self, info):
+    def listActions(self, info=None, object=None):
 
         """ Returns a list of actions to be displayed to the user.
 
@@ -243,9 +244,12 @@
 
         o Global actions are supplied by all workflows.
         """
+        if object is not None or info is None:
+            info = getOAI(self, object)
         chain = self.getChainFor(info.content)
         did = {}
         actions = []
+
         for wf_id in chain:
             did[wf_id] = 1
             wf = self.getWorkflowById(wf_id)



More information about the CMF-checkins mailing list