vendor/CMF/1.6.3/CMFCore

view ActionProviderBase.py @ 2:4c712d7bd1d7

Added tag 1.6.3 for changeset 1babb9d61518
author Georges Racinet on purity.racinet.fr <georges@racinet.fr>
date Fri, 09 Sep 2011 12:44:00 +0200
parents
children
line source
1 ##############################################################################
2 #
3 # Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
4 #
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE.
11 #
12 ##############################################################################
13 """ Implement a shared base for tools which provide actions.
15 $Id$
16 """
18 from AccessControl import ClassSecurityInfo
19 from Globals import DTMLFile
20 from Globals import InitializeClass
22 from ActionInformation import ActionInfo
23 from ActionInformation import ActionInformation
24 from ActionInformation import getOAI
25 from exceptions import AccessControl_Unauthorized
26 from Expression import getExprContext
27 from interfaces.portal_actions import ActionProvider as IActionProvider
28 from permissions import ManagePortal
29 from utils import _dtmldir
32 class ActionProviderBase:
33 """ Provide ActionTabs and management methods for ActionProviders
34 """
36 __implements__ = IActionProvider
38 security = ClassSecurityInfo()
40 _actions = ()
42 _actions_form = DTMLFile( 'editToolsActions', _dtmldir )
44 manage_options = ( { 'label' : 'Actions'
45 , 'action' : 'manage_editActionsForm'
46 , 'help' : ('CMFCore', 'Actions.stx')
47 }
48 ,
49 )
51 #
52 # ActionProvider interface
53 #
54 security.declarePrivate('listActions')
55 def listActions(self, info=None, object=None):
56 """ List all the actions defined by a provider.
57 """
58 return self._actions or ()
60 security.declarePrivate('getActionObject')
61 def getActionObject(self, action):
62 """Return the actions object or None if action doesn't exist.
63 """
64 # separate cataegory and id from action
65 sep = action.rfind('/')
66 if sep == -1:
67 raise ValueError('Actions must have the format <category>/<id>.')
68 category, id = action[:sep], action[sep+1:]
70 # search for action and return first one found
71 for ai in self.listActions():
72 if id == ai.getId() and category == ai.getCategory():
73 return ai
75 # no action found
76 return None
78 security.declarePublic('listActionInfos')
79 def listActionInfos(self, action_chain=None, object=None,
80 check_visibility=1, check_permissions=1,
81 check_condition=1, max=-1):
82 # List ActionInfo objects.
83 # (method is without docstring to disable publishing)
84 #
85 ec = self._getExprContext(object)
86 actions = self.listActions(object=object)
87 actions = [ ActionInfo(action, ec) for action in actions ]
89 if action_chain:
90 filtered_actions = []
91 if isinstance(action_chain, basestring):
92 action_chain = (action_chain,)
93 for action_ident in action_chain:
94 sep = action_ident.rfind('/')
95 category, id = action_ident[:sep], action_ident[sep+1:]
96 for ai in actions:
97 if id == ai['id'] and category == ai['category']:
98 filtered_actions.append(ai)
99 actions = filtered_actions
101 action_infos = []
102 for ai in actions:
103 if check_visibility and not ai['visible']:
104 continue
105 if check_permissions and not ai['allowed']:
106 continue
107 if check_condition and not ai['available']:
108 continue
109 action_infos.append(ai)
110 if max + 1 and len(action_infos) >= max:
111 break
112 return action_infos
114 security.declarePublic('getActionInfo')
115 def getActionInfo(self, action_chain, object=None, check_visibility=0,
116 check_condition=0):
117 """ Get an ActionInfo object specified by a chain of actions.
118 """
119 action_infos = self.listActionInfos(action_chain, object,
120 check_visibility=check_visibility,
121 check_permissions=False,
122 check_condition=check_condition)
123 if not action_infos:
124 if object is None:
125 provider = self
126 else:
127 provider = object
128 msg = 'Action "%s" not available for %s' % (
129 action_chain, '/'.join(provider.getPhysicalPath()))
130 raise ValueError(msg)
131 for ai in action_infos:
132 if ai['allowed']:
133 return ai
134 raise AccessControl_Unauthorized('You are not allowed to access any '
135 'of the specified Actions.')
137 #
138 # ZMI methods
139 #
140 security.declareProtected( ManagePortal, 'manage_editActionsForm' )
141 def manage_editActionsForm( self, REQUEST, manage_tabs_message=None ):
143 """ Show the 'Actions' management tab.
144 """
145 actions = [ ai.getMapping() for ai in self.listActions() ]
147 # possible_permissions is in AccessControl.Role.RoleManager.
148 pp = self.possible_permissions()
149 return self._actions_form( self
150 , REQUEST
151 , actions=actions
152 , possible_permissions=pp
153 , management_view='Actions'
154 , manage_tabs_message=manage_tabs_message
155 )
157 security.declareProtected( ManagePortal, 'addAction' )
158 def addAction( self
159 , id
160 , name
161 , action
162 , condition
163 , permission
164 , category
165 , visible=1
166 , REQUEST=None
167 ):
168 """ Add an action to our list.
169 """
170 if not name:
171 raise ValueError('A name is required.')
173 action = action and str(action) or ''
174 condition = condition and str(condition) or ''
176 if not isinstance(permission, tuple):
177 permission = (str(permission),)
179 new_actions = self._cloneActions()
181 new_action = ActionInformation( id=str(id)
182 , title=str(name)
183 , category=str(category)
184 , condition=condition
185 , permissions=permission
186 , visible=bool(visible)
187 , action=action
188 )
190 new_actions.append( new_action )
191 self._actions = tuple( new_actions )
193 if REQUEST is not None:
194 return self.manage_editActionsForm(
195 REQUEST, manage_tabs_message='Added.')
197 security.declareProtected( ManagePortal, 'changeActions' )
198 def changeActions( self, properties=None, REQUEST=None ):
200 """ Update our list of actions.
201 """
202 if properties is None:
203 properties = REQUEST
205 actions = []
207 for index in range( len( self._actions ) ):
208 actions.append( self._extractAction( properties, index ) )
210 self._actions = tuple( actions )
212 if REQUEST is not None:
213 return self.manage_editActionsForm(REQUEST, manage_tabs_message=
214 'Actions changed.')
216 security.declareProtected( ManagePortal, 'deleteActions' )
217 def deleteActions( self, selections=(), REQUEST=None ):
219 """ Delete actions indicated by indexes in 'selections'.
220 """
221 sels = list( map( int, selections ) ) # Convert to a list of integers.
223 old_actions = self._cloneActions()
224 new_actions = []
226 for index in range( len( old_actions ) ):
227 if index not in sels:
228 new_actions.append( old_actions[ index ] )
230 self._actions = tuple( new_actions )
232 if REQUEST is not None:
233 return self.manage_editActionsForm(
234 REQUEST, manage_tabs_message=(
235 'Deleted %d action(s).' % len(sels)))
237 security.declareProtected( ManagePortal, 'moveUpActions' )
238 def moveUpActions( self, selections=(), REQUEST=None ):
240 """ Move the specified actions up one slot in our list.
241 """
242 sels = list( map( int, selections ) ) # Convert to a list of integers.
243 sels.sort()
245 new_actions = self._cloneActions()
247 for idx in sels:
248 idx2 = idx - 1
249 if idx2 < 0:
250 # Wrap to the bottom.
251 idx2 = len(new_actions) - 1
252 # Swap.
253 a = new_actions[idx2]
254 new_actions[idx2] = new_actions[idx]
255 new_actions[idx] = a
257 self._actions = tuple( new_actions )
259 if REQUEST is not None:
260 return self.manage_editActionsForm(
261 REQUEST, manage_tabs_message=(
262 'Moved up %d action(s).' % len(sels)))
264 security.declareProtected( ManagePortal, 'moveDownActions' )
265 def moveDownActions( self, selections=(), REQUEST=None ):
267 """ Move the specified actions down one slot in our list.
268 """
269 sels = list( map( int, selections ) ) # Convert to a list of integers.
270 sels.sort()
271 sels.reverse()
273 new_actions = self._cloneActions()
275 for idx in sels:
276 idx2 = idx + 1
277 if idx2 >= len(new_actions):
278 # Wrap to the top.
279 idx2 = 0
280 # Swap.
281 a = new_actions[idx2]
282 new_actions[idx2] = new_actions[idx]
283 new_actions[idx] = a
285 self._actions = tuple( new_actions )
287 if REQUEST is not None:
288 return self.manage_editActionsForm(
289 REQUEST, manage_tabs_message=(
290 'Moved down %d action(s).' % len(sels)))
292 #
293 # Helper methods
294 #
295 security.declarePrivate( '_cloneActions' )
296 def _cloneActions( self ):
298 """ Return a list of actions, cloned from our current list.
299 """
300 return map( lambda x: x.clone(), list( self._actions ) )
302 security.declarePrivate( '_extractAction' )
303 def _extractAction( self, properties, index ):
305 """ Extract an ActionInformation from the funky form properties.
306 """
307 id = str( properties.get( 'id_%d' % index, '' ) )
308 title = str( properties.get( 'name_%d' % index, '' ) )
309 action = str( properties.get( 'action_%d' % index, '' ) )
310 condition = str( properties.get( 'condition_%d' % index, '' ) )
311 category = str( properties.get( 'category_%d' % index, '' ))
312 visible = bool( properties.get('visible_%d' % index, False) )
313 permissions = properties.get( 'permission_%d' % index, () )
315 if not title:
316 raise ValueError('A title is required.')
318 if category == '':
319 category = 'object'
321 if isinstance(permissions, basestring):
322 permissions = ( permissions, )
324 return ActionInformation( id=id
325 , title=title
326 , action=action
327 , condition=condition
328 , permissions=permissions
329 , category=category
330 , visible=visible
331 )
333 def _getOAI(self, object):
334 return getOAI(self, object)
336 def _getExprContext(self, object):
337 return getExprContext(self, object)
339 InitializeClass(ActionProviderBase)