Back to index

plone3  3.1.7
ActionProviderBase.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Implement a shared base for tools which provide actions.
00014 
00015 $Id: ActionProviderBase.py 77186 2007-06-28 19:06:19Z yuppie $
00016 """
00017 
00018 from AccessControl import ClassSecurityInfo
00019 from Globals import DTMLFile
00020 from Globals import InitializeClass
00021 from zope.interface import implements
00022 
00023 from ActionInformation import ActionInfo
00024 from ActionInformation import ActionInformation
00025 from ActionInformation import getOAI
00026 from exceptions import AccessControl_Unauthorized
00027 from Expression import getExprContext
00028 from interfaces import IActionProvider
00029 from interfaces.portal_actions import ActionProvider as z2IActionProvider
00030 from permissions import ManagePortal
00031 from utils import _dtmldir
00032 
00033 
00034 class ActionProviderBase:
00035 
00036     """ Provide ActionTabs and management methods for ActionProviders
00037     """
00038 
00039     implements(IActionProvider)
00040     __implements__ = z2IActionProvider
00041 
00042     security = ClassSecurityInfo()
00043 
00044     _actions = ()
00045 
00046     _actions_form = DTMLFile( 'editToolsActions', _dtmldir )
00047 
00048     manage_options = ( { 'label'  : 'Actions'
00049                        , 'action' : 'manage_editActionsForm'
00050                        , 'help'   : ('CMFCore', 'Actions.stx')
00051                        }
00052                      ,
00053                      )
00054 
00055     #
00056     #   ActionProvider interface
00057     #
00058     security.declarePrivate('listActions')
00059     def listActions(self, info=None, object=None):
00060         """ List all the actions defined by a provider.
00061         """
00062         return self._actions or ()
00063 
00064     security.declarePrivate('getActionObject')
00065     def getActionObject(self, action):
00066         """Return the actions object or None if action doesn't exist.
00067         """
00068         # separate cataegory and id from action
00069         sep = action.rfind('/')
00070         if sep == -1:
00071             raise ValueError('Actions must have the format <category>/<id>.')
00072         category, id = action[:sep], action[sep+1:]
00073 
00074         # search for action and return first one found
00075         for ai in self.listActions():
00076             try:
00077                 if id == ai.getId() and category == ai.getCategory():
00078                     return ai
00079             except AttributeError:
00080                 continue
00081 
00082         # no action found
00083         return None
00084 
00085     security.declarePublic('listActionInfos')
00086     def listActionInfos(self, action_chain=None, object=None,
00087                         check_visibility=1, check_permissions=1,
00088                         check_condition=1, max=-1):
00089         # List ActionInfo objects.
00090         # (method is without docstring to disable publishing)
00091         #
00092         ec = self._getExprContext(object)
00093         actions = self.listActions(object=object)
00094         actions = [ ActionInfo(action, ec) for action in actions ]
00095 
00096         if action_chain:
00097             filtered_actions = []
00098             if isinstance(action_chain, basestring):
00099                 action_chain = (action_chain,)
00100             for action_ident in action_chain:
00101                 sep = action_ident.rfind('/')
00102                 category, id = action_ident[:sep], action_ident[sep+1:]
00103                 for ai in actions:
00104                     if id == ai['id'] and category == ai['category']:
00105                         filtered_actions.append(ai)
00106             actions = filtered_actions
00107 
00108         action_infos = []
00109         for ai in actions:
00110             if check_visibility and not ai['visible']:
00111                 continue
00112             if check_permissions and not ai['allowed']:
00113                 continue
00114             if check_condition and not ai['available']:
00115                 continue
00116             action_infos.append(ai)
00117             if max + 1 and len(action_infos) >= max:
00118                 break
00119         return action_infos
00120 
00121     security.declarePublic('getActionInfo')
00122     def getActionInfo(self, action_chain, object=None, check_visibility=0,
00123                       check_condition=0):
00124         """ Get an ActionInfo object specified by a chain of actions.
00125         """
00126         action_infos = self.listActionInfos(action_chain, object,
00127                                             check_visibility=check_visibility,
00128                                             check_permissions=False,
00129                                             check_condition=check_condition)
00130         if not action_infos:
00131             if object is None:
00132                 provider = self
00133             else:
00134                 provider = object
00135             msg = 'Action "%s" not available for %s' % (
00136                         action_chain, '/'.join(provider.getPhysicalPath()))
00137             raise ValueError(msg)
00138         for ai in action_infos:
00139             if ai['allowed']:
00140                 return ai
00141         raise AccessControl_Unauthorized('You are not allowed to access any '
00142                                          'of the specified Actions.')
00143 
00144     #
00145     #   ZMI methods
00146     #
00147     security.declareProtected( ManagePortal, 'manage_editActionsForm' )
00148     def manage_editActionsForm( self, REQUEST, manage_tabs_message=None ):
00149 
00150         """ Show the 'Actions' management tab.
00151         """
00152         actions = [ ai.getMapping() for ai in self.listActions() ]
00153 
00154         # possible_permissions is in AccessControl.Role.RoleManager.
00155         pp = self.possible_permissions()
00156         return self._actions_form( self
00157                                  , REQUEST
00158                                  , actions=actions
00159                                  , possible_permissions=pp
00160                                  , management_view='Actions'
00161                                  , manage_tabs_message=manage_tabs_message
00162                                  )
00163 
00164     security.declareProtected( ManagePortal, 'addAction' )
00165     def addAction( self
00166                  , id
00167                  , name
00168                  , action
00169                  , condition
00170                  , permission
00171                  , category
00172                  , visible=1
00173                  , REQUEST=None
00174                  ):
00175         """ Add an action to our list.
00176         """
00177         if not name:
00178             raise ValueError('A name is required.')
00179 
00180         action = action and str(action) or ''
00181         condition = condition and str(condition) or ''
00182 
00183         if not isinstance(permission, tuple):
00184             permission = (str(permission),)
00185 
00186         new_actions = self._cloneActions()
00187 
00188         new_action = ActionInformation( id=str(id)
00189                                       , title=str(name)
00190                                       , category=str(category)
00191                                       , condition=condition
00192                                       , permissions=permission
00193                                       , visible=bool(visible)
00194                                       , action=action
00195                                       )
00196 
00197         new_actions.append( new_action )
00198         self._actions = tuple( new_actions )
00199 
00200         if REQUEST is not None:
00201             return self.manage_editActionsForm(
00202                 REQUEST, manage_tabs_message='Added.')
00203 
00204     security.declareProtected( ManagePortal, 'changeActions' )
00205     def changeActions( self, properties=None, REQUEST=None ):
00206 
00207         """ Update our list of actions.
00208         """
00209         if properties is None:
00210             properties = REQUEST
00211 
00212         actions = []
00213 
00214         for index in range( len( self._actions ) ):
00215             actions.append( self._extractAction( properties, index ) )
00216 
00217         self._actions = tuple( actions )
00218 
00219         if REQUEST is not None:
00220             return self.manage_editActionsForm(REQUEST, manage_tabs_message=
00221                                                'Actions changed.')
00222 
00223     security.declareProtected( ManagePortal, 'deleteActions' )
00224     def deleteActions( self, selections=(), REQUEST=None ):
00225 
00226         """ Delete actions indicated by indexes in 'selections'.
00227         """
00228         sels = list( map( int, selections ) )  # Convert to a list of integers.
00229 
00230         old_actions = self._cloneActions()
00231         new_actions = []
00232 
00233         for index in range( len( old_actions ) ):
00234             if index not in sels:
00235                 new_actions.append( old_actions[ index ] )
00236 
00237         self._actions = tuple( new_actions )
00238 
00239         if REQUEST is not None:
00240             return self.manage_editActionsForm(
00241                 REQUEST, manage_tabs_message=(
00242                 'Deleted %d action(s).' % len(sels)))
00243 
00244     security.declareProtected( ManagePortal, 'moveUpActions' )
00245     def moveUpActions( self, selections=(), REQUEST=None ):
00246 
00247         """ Move the specified actions up one slot in our list.
00248         """
00249         sels = list( map( int, selections ) )  # Convert to a list of integers.
00250         sels.sort()
00251 
00252         new_actions = self._cloneActions()
00253 
00254         for idx in sels:
00255             idx2 = idx - 1
00256             if idx2 < 0:
00257                 # Wrap to the bottom.
00258                 idx2 = len(new_actions) - 1
00259             # Swap.
00260             a = new_actions[idx2]
00261             new_actions[idx2] = new_actions[idx]
00262             new_actions[idx] = a
00263 
00264         self._actions = tuple( new_actions )
00265 
00266         if REQUEST is not None:
00267             return self.manage_editActionsForm(
00268                 REQUEST, manage_tabs_message=(
00269                 'Moved up %d action(s).' % len(sels)))
00270 
00271     security.declareProtected( ManagePortal, 'moveDownActions' )
00272     def moveDownActions( self, selections=(), REQUEST=None ):
00273 
00274         """ Move the specified actions down one slot in our list.
00275         """
00276         sels = list( map( int, selections ) )  # Convert to a list of integers.
00277         sels.sort()
00278         sels.reverse()
00279 
00280         new_actions = self._cloneActions()
00281 
00282         for idx in sels:
00283             idx2 = idx + 1
00284             if idx2 >= len(new_actions):
00285                 # Wrap to the top.
00286                 idx2 = 0
00287             # Swap.
00288             a = new_actions[idx2]
00289             new_actions[idx2] = new_actions[idx]
00290             new_actions[idx] = a
00291 
00292         self._actions = tuple( new_actions )
00293 
00294         if REQUEST is not None:
00295             return self.manage_editActionsForm(
00296                 REQUEST, manage_tabs_message=(
00297                 'Moved down %d action(s).' % len(sels)))
00298 
00299     #
00300     #   Helper methods
00301     #
00302     security.declarePrivate( '_cloneActions' )
00303     def _cloneActions( self ):
00304 
00305         """ Return a list of actions, cloned from our current list.
00306         """
00307         return map( lambda x: x.clone(), list( self._actions ) )
00308 
00309     security.declarePrivate( '_extractAction' )
00310     def _extractAction( self, properties, index ):
00311 
00312         """ Extract an ActionInformation from the funky form properties.
00313         """
00314         id          = str( properties.get( 'id_%d'          % index, '' ) )
00315         title       = str( properties.get( 'name_%d'        % index, '' ) )
00316         action      = str( properties.get( 'action_%d'      % index, '' ) )
00317         condition   = str( properties.get( 'condition_%d'   % index, '' ) )
00318         category    = str( properties.get( 'category_%d'    % index, '' ))
00319         visible     = bool( properties.get('visible_%d'     % index, False) )
00320         permissions =      properties.get( 'permission_%d'  % index, () )
00321 
00322         if not title:
00323             raise ValueError('A title is required.')
00324 
00325         if category == '':
00326             category = 'object'
00327 
00328         if isinstance(permissions, basestring):
00329             permissions = ( permissions, )
00330 
00331         return ActionInformation( id=id
00332                                 , title=title
00333                                 , action=action
00334                                 , condition=condition
00335                                 , permissions=permissions
00336                                 , category=category
00337                                 , visible=visible
00338                                 )
00339 
00340     def _getOAI(self, object):
00341         return getOAI(self, object)
00342 
00343     def _getExprContext(self, object):
00344         return getExprContext(self, object)
00345 
00346 InitializeClass(ActionProviderBase)