From andrew@zope.com Wed Jan 2 22:03:34 2002 From: andrew@zope.com (Andrew Sawyers) Date: Wed, 2 Jan 2002 17:03:34 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/dtml - editToolsActions.dtml:1.1.2.1 manageActionProviders.dtml:1.1.2.1 Message-ID: <200201022203.g02M3YH21516@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/dtml In directory cvs.zope.org:/tmp/cvs-serv20833/CMFCore/dtml Added Files: Tag: andrew_ttw_actions-branch editToolsActions.dtml manageActionProviders.dtml Log Message: *Changes to support Tools TTW Actions *Changes to support TTW Action Provider configuration *Docs and Test coming soon... === Added File CMF/CMFCore/dtml/editToolsActions.dtml === &dtml-form_title; &dtml-form_title; Name Id Action Condition Permission (none) &dtml-sequence-item; Category Visible? Add an action Name Id Action Condition Permission (none) &dtml-sequence-item; Category Visible? === Added File CMF/CMFCore/dtml/manageActionProviders.dtml === manage action providers Action Providers Name &dtml-sequence-item; From andrew@zope.com Wed Jan 2 22:03:35 2002 From: andrew@zope.com (Andrew Sawyers) Date: Wed, 2 Jan 2002 17:03:35 -0500 Subject: [CMF-checkins] CVS: CMF/CMFDefault - DiscussionTool.py:1.6.12.1 MembershipTool.py:1.17.12.1 MetadataTool.py:1.9.12.1 RegistrationTool.py:1.8.8.1 SyndicationTool.py:1.9.12.1 URLTool.py:1.7.12.1 Message-ID: <200201022203.g02M3ZC21532@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFDefault In directory cvs.zope.org:/tmp/cvs-serv20833/CMFDefault Modified Files: Tag: andrew_ttw_actions-branch DiscussionTool.py MembershipTool.py MetadataTool.py RegistrationTool.py SyndicationTool.py URLTool.py Log Message: *Changes to support Tools TTW Actions *Changes to support TTW Action Provider configuration *Docs and Test coming soon... === CMF/CMFDefault/DiscussionTool.py 1.6 => 1.6.12.1 === from utils import _dtmldir from DiscussionItem import DiscussionItemContainer +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.Expression import Expression class DiscussionNotAllowed( Exception ): pass -class DiscussionTool( UniqueObject, SimpleItem ): +class DiscussionTool( UniqueObject, SimpleItem, ActionProviderBase ): id = 'portal_discussion' meta_type = 'Default Discussion Tool' + _actions = [ActionInformation(id='reply' + , title='Reply' + , action=Expression( + text='string: ${object_url}/discussion_reply_form') + , condition=Expression( + text='python: object is not None and ' + + 'portal.portal_discussion.isDiscussionAllowedFor(object)') + , permissions=('Reply to item',) + , category='object' + , visible=1 + )] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = (ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + SimpleItem.manage_options + ) + SimpleItem.manage_options) # # ZMI methods @@ -52,6 +67,13 @@ # 'portal_discussion' interface methods # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return available actions via tool. + """ + return self._actions + security.declarePublic( 'overrideDiscussionFor' ) def overrideDiscussionFor(self, content, allowDiscussion): """ @@ -96,29 +118,6 @@ if typeInfo: return typeInfo.allowDiscussion() return 0 - - # - # ActionProvider interface - # - security.declarePrivate( 'listActions' ) - def listActions(self, info): - # Return actions for reply and show replies - content = info.content - if content is None or not self.isDiscussionAllowedFor(content): - return None - - discussion = self.getDiscussionFor(content) - discussion_url = info.content_url - - actions = ( - {'name': 'Reply', - 'url': discussion_url + '/discussion_reply_form', - 'permissions': ['Reply to item'], - 'category': 'object' - }, - ) - - return actions # # Utility methods === CMF/CMFDefault/MembershipTool.py 1.17 => 1.17.12.1 === from Products.CMFCore.utils import _getAuthenticatedUser, _checkPermission from Products.CMFCore.utils import getToolByName +from Products.CMFCore.ActionsTool import ActionInformation import Products.CMFCore.MembershipTool from Products.CMFCore.PortalFolder import manage_addPortalFolder import Document from Globals import InitializeClass, DTMLFile from AccessControl import ClassSecurityInfo +from Products.CMFCore.Expression import Expression from Products.CMFCore.CMFCorePermissions import View, AccessContentsInformation from Products.CMFCore.CMFCorePermissions import ListPortalMembers, AddPortalMember from Products.CMFCore.CMFCorePermissions import ManagePortal @@ -40,10 +42,92 @@ in the Tool Box on the left. ''' - class MembershipTool ( Products.CMFCore.MembershipTool.MembershipTool ): """ """ + _actions =[ActionInformation(id='join' + , title='Join' + , description='Click here to Join' + , action=Expression( + text='string: ${portal_url}/join_form') + , permissions=(View,) + , category='user' + , condition=Expression(text='not: member') + , visible=1 + ) + , ActionInformation(id='login' + , title='Login' + , description='Click here to Login' + , action=Expression( + text='string: ${portal_url}/login_form') + , permissions=(View,) + , category='user' + , condition=Expression(text='not: member') + , visible=1 + ) + , ActionInformation(id='preferences' + , title='Preferences' + , description='Change your user preferences' + , action=Expression( + text='string: ${portal_url}/personalize_form') + , permissions=(View,) + , category='user' + , condition=Expression(text='member') + , visible=1 + ) + , ActionInformation(id='logout' + , title='Log out' + , description='Click here to logout' + , action=Expression( + text='string: ${portal_url}/logout') + , permissions=(View,) + , category='user' + , condition=Expression(text='member') + , visible=1 + ) + , ActionInformation(id='configPortal' + , title='Reconfigure Portal' + , description='Reconfigure the portal' + , action=Expression( + text='string: ${portal_url}/reconfig_form') + , permissions=(ManagePortal,) + , category='global' + , condition=None + , visible=1 + ) + , ActionInformation(id='addFavorite' + , title='Add to favorites' + , description='Add this item to your favorites' + , action=Expression( + text='string: ${portal_url}/addtoFavorites') + , permissions=(View,) + , category='user' + , condition=Expression( + text='python: portal.portal_membership.getHomeFolder()') + , visible=1 + ) + , ActionInformation(id='mystuff' + , title='my stuff' + , description='Goto your home folder' + , action=Expression(text='member/getHomeUrl') + , permissions=(View,) + , category='user' + , condition=Expression( + text='python: member and portal.portal_membership.getHomeFolder()') + , visible=1 + ) + , ActionInformation(id='favorites' + , title='My favorites' + , description='Browser your favorites' + , action=Expression( + text='python: member.getHomeUrl() + \'/Favorites/folder_contents\'') + , permissions=(View,) + , category='user' + , condition=Expression( + text='python: member and hasattr(portal.portal_membership.getHomeFolder(), \'Favorites\')') + , visible=1 + ) + ] meta_type = 'Default Membership Tool' @@ -151,63 +235,8 @@ return None security.declarePrivate( 'listActions' ) - def listActions(self, info): - '''Lists actions available to the user.''' - user_actions = None - portal_url = info.portal_url - if info.isAnonymous: - user_actions = ( - {'name': 'Log in', - 'url': portal_url + '/login_form', - 'permissions': [], - 'category': 'user'}, - {'name': 'Join', - 'url': portal_url + '/join_form', - 'permissions': [AddPortalMember], - 'category': 'user'}, - ) - - if not info.isAnonymous: - home_folder = self.getHomeFolder() - homeUrl = self.getHomeUrl() - user_actions = ( - {'name': 'Preferences', - 'url': portal_url + '/personalize_form', - 'permissions': [], - 'category': 'user'}, - {'name': 'Log out', - 'url': portal_url + '/logout', - 'permissions' : [], - 'category': 'user'}, - {'name': 'Reconfigure portal', - 'url': portal_url + '/reconfig_form', - 'permissions': ['Manage portal'], - 'category': 'global'}, - ) - - if homeUrl is not None: - content_url = info.content_url - actions = ( - {'name': 'Add to Favorites', - 'url': ( content_url + '/addtoFavorites' ), - 'permissions' : [], - 'category': 'user'}, - {'name': 'My Stuff', - 'url': homeUrl + '/folder_contents', - 'permissions': [], - 'category': 'user'}, - ) - user_actions = user_actions + actions - - if hasattr( home_folder, 'Favorites' ): - added_actions = ( - {'name': 'My Favorites', - 'url' : homeUrl + '/Favorites/folder_contents', - 'permissions': [], - 'category': 'user'},) - user_actions = user_actions + added_actions - - return user_actions - + def listActions(self, info=None): + '''Lists actions available through the tool.''' + return self._actions InitializeClass(MembershipTool) === CMF/CMFDefault/MetadataTool.py 1.9 => 1.9.12.1 === from AccessControl import ClassSecurityInfo, getSecurityManager from Products.CMFCore import CMFCorePermissions +from Products.CMFCore.ActionProviderBase import ActionProviderBase from utils import _dtmldir class MetadataElementPolicy( Persistent ): @@ -190,11 +191,13 @@ class MetadataError( Exception ): pass -class MetadataTool( UniqueObject, SimpleItem ): +class MetadataTool( UniqueObject, SimpleItem, ActionProviderBase ): id = 'portal_metadata' meta_type = 'Default Metadata Tool' + _actions = [] + security = ClassSecurityInfo() # @@ -225,7 +228,8 @@ # # ZMI methods # - manage_options = ( ( { 'label' : 'Overview' + manage_options = ( ActionProviderBase.manage_options + + ( { 'label' : 'Overview' , 'action' : 'manage_overview' } , { 'label' : 'Properties' @@ -248,6 +252,13 @@ security.declareProtected( CMFCorePermissions.ManagePortal , 'propertiesForm' ) propertiesForm = DTMLFile( 'metadataProperties', _dtmldir ) + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return actions provided via tool. + """ + return self._actions security.declareProtected( CMFCorePermissions.ManagePortal , 'editProperties' ) === CMF/CMFDefault/RegistrationTool.py 1.8 => 1.8.8.1 === from Products.CMFCore.utils import UniqueObject from Products.CMFCore.utils import _checkPermission, getToolByName +from Products.CMFCore.ActionProviderBase import ActionProviderBase from Products.CMFCore.RegistrationTool import RegistrationTool from Globals import InitializeClass, DTMLFile @@ -27,9 +28,11 @@ from Products.CMFCore import CMFCorePermissions from utils import _dtmldir -class RegistrationTool (RegistrationTool): +class RegistrationTool (RegistrationTool, ActionProviderBase): meta_type = 'Default Registration Tool' + _actions = [] + security = ClassSecurityInfo() # @@ -37,6 +40,11 @@ # security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) + + manage_options = ( ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } + , + )) manage_overview = DTMLFile( 'explainRegistrationTool', _dtmldir ) # @@ -55,10 +63,11 @@ return None security.declarePublic('listActions') - def listActions(self, info): + def listActions(self, info=None): """ + Return actions provided via tool. """ - return None + return self._actions security.declarePublic( 'testPropertiesValidity' ) def testPropertiesValidity(self, props, member=None): === CMF/CMFDefault/SyndicationTool.py 1.9 => 1.9.12.1 === from Products.CMFCore.CMFCorePermissions import ManageProperties from Products.CMFCore.CMFCorePermissions import AccessContentsInformation +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression import Products.CMFCore.CMFCorePermissions from Products.CMFCore.PortalFolder import PortalFolder from SyndicationInfo import SyndicationInformation _dtmldir = os.path.join( package_home( globals() ), 'dtml' ) -class SyndicationTool (UniqueObject, SimpleItem): +class SyndicationTool (UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_syndication' meta_type = 'Default Syndication Tool' + _actions = [ActionInformation(id='syndication' + , title='Syndication' + , action=Expression( + text='string: ${folder_url}/synPropertiesForm') + , condition=Expression( + text='python: folder is object') + , permissions=(ManageProperties,) + , category='folder' + , visible=1 + )] + security = ClassSecurityInfo() #Default Sitewide Values @@ -46,7 +60,8 @@ max_items = 15 #ZMI Methods - manage_options = (({'label' : 'Overview' + manage_options = (ActionProviderBase.manage_options + + ({'label' : 'Overview' ,'action' : 'overview' , 'help' : ('CMFDefault', 'Syndication-Tool_Overview.stx') } ,{'label' : 'Properties' @@ -69,6 +84,13 @@ security.declareProtected(ManagePortal, 'reportForm') reportForm = HTMLFile('synReports', _dtmldir) + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return actions provided by tool + """ + return self._actions + security.declareProtected(ManagePortal, 'editProperties') def editProperties(self , updatePeriod=None === CMF/CMFDefault/URLTool.py 1.7 => 1.7.12.1 === security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } , ) + SimpleItem.manage_options From andrew@zope.com Wed Jan 2 22:03:35 2002 From: andrew@zope.com (Andrew Sawyers) Date: Wed, 2 Jan 2002 17:03:35 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.1.2.1 ActionProviderBase.py:1.1.2.1 Expression.py:1.1.2.1 ActionsTool.py:1.19.10.1 CatalogTool.py:1.21.14.1 MemberDataTool.py:1.12.14.1 MembershipTool.py:1.16.14.1 PortalFolder.py:1.28.10.1 RegistrationTool.py:1.7.14.1 SkinsTool.py:1.11.14.1 TypesTool.py:1.26.14.1 UndoTool.py:1.4.14.1 WorkflowTool.py:1.19.4.1 Message-ID: <200201022203.g02M3Zl21533@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv20833/CMFCore Modified Files: Tag: andrew_ttw_actions-branch ActionsTool.py CatalogTool.py MemberDataTool.py MembershipTool.py PortalFolder.py RegistrationTool.py SkinsTool.py TypesTool.py UndoTool.py WorkflowTool.py Added Files: Tag: andrew_ttw_actions-branch ActionInformation.py ActionProviderBase.py Expression.py Log Message: *Changes to support Tools TTW Actions *Changes to support TTW Action Provider configuration *Docs and Test coming soon... === Added File CMF/CMFCore/ActionInformation.py === ############################################################################## # # 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 # ############################################################################## """Basic action list tool. $Id: ActionInformation.py,v 1.1.2.1 2002/01/02 22:03:32 andrew Exp $ """ __version__='$Revision: 1.1.2.1 $'[11:-2] from utils import SimpleItemWithProperties, _dtmldir, getToolByName import CMFCorePermissions from AccessControl import ClassSecurityInfo from Acquisition import aq_inner, aq_parent from Globals import InitializeClass, DTMLFile class ActionInformation(SimpleItemWithProperties): """ Represent a single action which the user can select from a list and execut in some context. """ _isActionInformation = 1 __allow_access_to_unprotected_subobjects__ = 1 manage_options = (SimpleItemWithProperties.manage_options[:1] + ({'label': 'Actions', 'action': 'manage_editActionsForm'},) + SimpleItemWithProperties.manage_options[1:]) security = ClassSecurityInfo() security.declareProtected(CMFCorePermissions.ManagePortal , 'manage_editProperties' , 'manage_changeProperties' , 'manage_propertiesForm' ) _basic_properties = ( {'id': 'title', 'type': 'string', 'mode': 'w', 'label': 'Title'} , {'id': 'description', 'type': 'text', 'mode': 'w', 'label': 'Description'} , {'id': 'category', 'type': 'string', 'mode': 'w', 'label': 'Category'} , {'id': 'priority', 'type': 'boolean', 'mode': 'w', 'label': 'Priority'} ) title = '' description = '' category = '' priority = 0 visible = 1 _action = '' def __init__(self , id , title='' , description='' , category='object' , condition='' , permissions=() , priority=10 , visible=1 , action=''): """ Setup an instance """ 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 security.declareProtected(CMFCorePermissions.View, 'Title') def Title(self): """ Return the Action title - name """ if self.title: return self.title else: return self.getId() security.declareProtected(CMFCorePermissions.View, 'Description') def Description(self): """ Return a description of the action """ return self.description security.declarePrivate('testCondition') def testCondition(self, ec): """ Evaluate condition and return 0 or 1 """ if self.condition: return self.condition(ec) else: return 1 security.declarePublic('getAction') def getAction(self, ec): """ Return the action, which is an TALES expresssion """ if self._action: aa = self._action(ec) else: aa = '' action = {} action['id'] = self.id action['name'] = self.Title() action['url'] = aa action['permissions'] = self.getPermissions() action['category'] = self.getCategory() action['visible'] = self.getVisibility() return action security.declarePublic('getCondition') def getCondition(self): """ If not an empty string or None, evaluate the expression """ if self.condition: return self.condition.text else: return self.condition security.declarePublic('getPermission') def getPermissions(self): """ Return the permission if any required for a user to execute the action """ return self.permissions security.declarePublic('getCategory') def getCategory(self): """ Return the category for which the action is """ if self.category: return self.category else: return 'object' security.declarePublic('getVisibility') def getVisibility(self): """ Return boolean for whether the action is visible in the UI """ if self.visible: return self.visible else: return 1 security.declarePublic('getPriority') def getPriority(self): """ Return integer priority for sorting """ if self.priority: return self.priority else: return 10 InitializeClass(ActionInformation) class oai: #Provided for backwards compatability # Provides information that may be needed when constructing the list of # available actions. __allow_access_to_unprotected_subobjects__ = 1 def __init__(self, tool, folder, object=None): self.portal = portal = aq_parent(aq_inner(tool)) membership = getToolByName(tool, 'portal_membership') self.isAnonymous = membership.isAnonymousUser() self.portal_url = portal.absolute_url() if folder is not None: self.folder_url = folder.absolute_url() self.folder = folder else: self.folder_url = self.portal_url self.folder = portal self.content = object if object is not None: self.content_url = object.absolute_url() else: self.content_url = None def __getitem__(self, name): # Mapping interface for easy string formatting. if name[:1] == '_': raise KeyError, name if hasattr(self, name): return getattr(self, name) raise KeyError, name === Added File CMF/CMFCore/ActionProviderBase.py === ############################################################################## # # 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 # ############################################################################## from OFS.SimpleItem import SimpleItem from Globals import DTMLFile from CMFCorePermissions import ManagePortal from utils import _dtmldir, cookString from AccessControl import ClassSecurityInfo from ActionInformation import ActionInformation from Expression import Expression """Basic action list tool. $Id: ActionProviderBase.py,v 1.1.2.1 2002/01/02 22:03:32 andrew Exp $ """ __version__='$Revision: 1.1.2.1 $'[11:-2] class ActionProviderBase: """ Provide ActionTabs and management methods for ActionProviders """ _actions = [] security = ClassSecurityInfo() _actions_form = DTMLFile( 'editToolsActions', _dtmldir ) manage_options = ({ 'label' : 'Actions', 'action' : 'manage_editActionsForm' } , ) security.declarePrivate('listActions') def listActions(self): """ Return all the actions defined by a tool """ if self._actions: return self._actions else: return None security.declareProtected(ManagePortal, 'manage_editActionsForm') def manage_editActionsForm(self, REQUEST, manage_tabs_message=None): """ Shows the 'Actions' management tab. """ actions = [] if self.listActions() is not None: for a in self.listActions(): a1 = {} a1['id'] = a.getId() a1['name'] = a.Title() p = a.getPermissions() if p: a1['permission'] = p[0] else: a1['permission'] = '' if not a.getCategory(): a1['category'] = 'object' else: a1['category'] = a.getCategory() if not a.getVisibility(): a1['visible'] = 1 else: a1['visible'] = a.getVisibility() if a._action: a1['action'] = a._action.text else: a1['action'] = '' if a.condition: a1['condition'] = a.getCondition() else: a1['condition'] = '' actions.append(a1) # possible_permissions is in AccessControl.Role.RoleManager. pp = self.possible_permissions() return self._actions_form(self, REQUEST, actions=actions, possible_permissions=pp, management_view='Actions', manage_tabs_message=manage_tabs_message) security.declareProtected(ManagePortal, 'addAction') def addAction( self , id , name , action , condition , permission , category , visible=1 , REQUEST=None ): """ Adds an action to the list. """ al = self._actions if not name: raise ValueError('A name is required.') if action: a_expr = Expression(text=str(action)) else: a_expr = '' if condition: c_expr = Expression(text=str(condition)) else: c_expr = '' al.append(ActionInformation(id=str(id) , title=str(name) , action=a_expr , condition=c_expr , permissions=(str(permission),) , category=str(category) , visible=int(visible) )) self._actions = al if REQUEST is not None: return self.manage_editActionsForm( REQUEST, manage_tabs_message='Added.') security.declareProtected(ManagePortal, 'changeActions') def changeActions(self, properties=None, REQUEST=None): """ Changes the _actions. """ if properties is None: properties = REQUEST actions = [] for idx in range(len(self._actions)): s_idx = str(idx) action = { 'id': str(properties.get('id_' + s_idx, '')), 'name': str(properties.get('name_' + s_idx, '')), 'action': str(properties.get('action_' + s_idx, '')), 'condition': str(properties.get('condition_' + s_idx, '')), 'permissions': (properties.get('permission_' + s_idx, ()),), 'category': str(properties.get('category_' + s_idx, 'object')), 'visible': not not properties.get('visible_' + s_idx, 0), } if not action['name']: raise ValueError('A name is required.') a = self._actions[idx] a.id = action['id'] a.title = action['name'] if not a._action: a._action = Expression(text=action['action']) else: a._action.text = action['action'] if not a.condition: a.condition = Expression(text=action['condition']) else: del(a.condition) a.condition= Expression(text = action['condition']) a.permissions = action['permissions'] a.category = action['category'] a.visible = action['visible'] if REQUEST is not None: return self.manage_editActionsForm(REQUEST, manage_tabs_message= 'Actions changed.') security.declareProtected(ManagePortal, 'deleteActions') def deleteActions(self, selections=(), REQUEST=None): """ Deletes actions. """ actions = list(self._actions) sels = list(map(int, selections)) # Convert to a list of integers. sels.sort() sels.reverse() for idx in sels: del actions[idx] self._actions = actions if REQUEST is not None: return self.manage_editActionsForm( REQUEST, manage_tabs_message=( 'Deleted %d action(s).' % len(sels))) security.declareProtected(ManagePortal, 'moveUpActions') def moveUpActions(self, selections=(), REQUEST=None): """ Moves the specified actions up one slot. """ actions = list(self._actions) sels = list(map(int, selections)) # Convert to a list of integers. sels.sort() for idx in sels: idx2 = idx - 1 if idx2 < 0: # Wrap to the bottom. idx2 = len(actions) - 1 # Swap. a = actions[idx2] actions[idx2] = actions[idx] actions[idx] = a self._actions = actions if REQUEST is not None: return self.manage_editActionsForm( REQUEST, manage_tabs_message=( 'Moved up %d action(s).' % len(sels))) security.declareProtected(ManagePortal, 'moveDownActions') def moveDownActions(self, selections=(), REQUEST=None): """ Moves the specified actions down one slot. """ actions = list(self._actions) sels = list(map(int, selections)) # Convert to a list of integers. sels.sort() sels.reverse() for idx in sels: idx2 = idx + 1 if idx2 >= len(actions): # Wrap to the top. idx2 = 0 # Swap. a = actions[idx2] actions[idx2] = actions[idx] actions[idx] = a self._actions = actions if REQUEST is not None: return self.manage_editActionsForm( REQUEST, manage_tabs_message=( 'Moved down %d action(s).' % len(sels))) === Added File CMF/CMFCore/Expression.py === ############################################################################## # # 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. $Id: Expression.py,v 1.1.2.1 2002/01/02 22:03:32 andrew Exp $ ''' __version__='$Revision: 1.1.2.1 $'[11:-2] import Globals from Globals import Persistent from Acquisition import aq_inner, aq_parent from AccessControl import getSecurityManager, ClassSecurityInfo from utils import getToolByName from Products.PageTemplates.Expressions import getEngine from Products.PageTemplates.TALES import SafeMapping from Products.PageTemplates.PageTemplate import ModuleImporter class Expression (Persistent): text = '' _v_compiled = None security = ClassSecurityInfo() def __init__(self, text): self.text = text self._v_compiled = getEngine().compile(text) def __call__(self, econtext): compiled = self._v_compiled if compiled is None: compiled = self._v_compiled = getEngine().compile(self.text) # ?? Maybe expressions should manipulate the security # context stack. res = compiled(econtext) if isinstance(res, Exception): raise res #print 'returning %s from %s' % (`res`, self.text) return res Globals.InitializeClass(Expression) def createExprContext(folder, portal, object): ''' An expression context provides names for TALES expressions. ''' pm = getToolByName(portal, 'portal_membership') if object is None: object_url = '' else: object_url = object.absolute_url() if pm.isAnonymousUser(): member = None else: member = pm.getAuthenticatedMember() data = { 'object_url': object_url, 'folder_url': folder.absolute_url(), 'portal_url': portal.absolute_url(), 'object': object, 'content': object, 'folder': folder, 'portal': portal, 'nothing': None, 'request': getattr( object, 'REQUEST', None ), 'modules': ModuleImporter, 'member': member, } return getEngine().getContext(data) === CMF/CMFCore/ActionsTool.py 1.19 => 1.19.10.1 === -from utils import UniqueObject, _getAuthenticatedUser, _checkPermission -from utils import getToolByName, _dtmldir +import OFS +from utils import UniqueObject, SimpleItemWithProperties, _getAuthenticatedUser, _checkPermission +from utils import getToolByName, _dtmldir, cookString import CMFCorePermissions from OFS.SimpleItem import SimpleItem from Globals import InitializeClass, DTMLFile, package_home @@ -27,60 +28,57 @@ from Acquisition import aq_base, aq_inner, aq_parent from AccessControl import ClassSecurityInfo from string import join +from Expression import Expression, createExprContext +from ActionInformation import ActionInformation, oai +from ActionProviderBase import ActionProviderBase -class ActionInformation: - # Provides information that may be needed when constructing the list of - # available actions. - __allow_access_to_unprotected_subobjects__ = 1 - - def __init__(self, tool, folder, object=None): - self.portal = portal = aq_parent(aq_inner(tool)) - membership = getToolByName(tool, 'portal_membership') - self.isAnonymous = membership.isAnonymousUser() - self.portal_url = portal.absolute_url() - if folder is not None: - self.folder_url = folder.absolute_url() - self.folder = folder - else: - self.folder_url = self.portal_url - self.folder = portal - self.content = object - if object is not None: - self.content_url = object.absolute_url() - else: - self.content_url = None - def __getitem__(self, name): - # Mapping interface for easy string formatting. - if name[:1] == '_': - raise KeyError, name - if hasattr(self, name): - return getattr(self, name) - raise KeyError, name - - -class ActionsTool (UniqueObject, SimpleItem): +class ActionsTool(UniqueObject, OFS.Folder.Folder, ActionProviderBase): """ Weave together the various sources of "actions" which are apropos to the current user and context. """ id = 'portal_actions' + _actions = [ActionInformation(id='folderContents' + , title='Folder contents' + , action=Expression( + text='string: ${folder_url}/folder_contents') + , condition=Expression( + text='python: folder is not object') + , permissions=('List folder contents',) + , category='object' + , visible=1 + ) + , ActionInformation(id='folderContents' + , title='Folder contents' + , action=Expression( + text='string: ${folder_url}/folder_contents') + , condition=Expression( + text='python: folder is object') + , permissions=('List folder contents',) + , category='folder' + , visible=1 + )] + meta_type = 'CMF Actions Tool' - action_providers = ( 'portal_actions' - , 'portal_memberdata' - , 'portal_registration' - , 'portal_discussion' - , 'portal_membership' - , 'portal_workflow' - , 'portal_undo' - ) + action_providers = ('portal_membership' + , 'portal_memberdata' + , 'portal_actions' + , 'portal_registration' + , 'portal_discussion' + , 'portal_undo' + , 'portal_syndication' + , 'portal_workflow') security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } - , - ) + SimpleItem.manage_options + manage_options = ( ActionProviderBase.manage_options + + ({'label' : 'Action Providers', 'action' : 'manage_actionProviders'} + , { 'label' : 'Overview', 'action' : 'manage_overview' } + , + ) + OFS.Folder.Folder.manage_options + ) # # ZMI methods @@ -88,19 +86,56 @@ security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) manage_overview = DTMLFile( 'explainActionsTool', _dtmldir ) + manage_actionProviders = DTMLFile('manageActionProviders', _dtmldir) # # Programmatically manipulate the list of action providers # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Lists actions available through the tool. + """ + return self._actions + security.declareProtected( CMFCorePermissions.ManagePortal , 'listActionProviders' ) - def listActionProviders( self ): + def listActionProviders(self): """ returns a sequence of action providers known by this tool """ return self.action_providers + security.declareProtected(CMFCorePermissions.ManagePortal + , 'manage_aproviders') + def manage_aproviders(self + , apname='' + , chosen=() + , add_provider=0 + , del_provider=0 + , REQUEST=None): + """ + Manage TTW Action Providers + """ + #import pdb; pdb.set_trace() + providers = self.listActionProviders() + new_providers = [] + if add_provider: + providers.append(apname) + elif del_provider: + for item in providers: + if item not in chosen: + new_providers.append(item) + providers = new_providers + self.action_providers = providers + if REQUEST is not None: + return self.manage_actionProviders(self + , REQUEST + , manage_tabs_message='Properties changed.') + + + security.declareProtected( CMFCorePermissions.ManagePortal , 'addActionProvider' ) @@ -111,26 +146,6 @@ p_new = p_old + ( provider_name, ) self.action_providers = p_new - security.declarePrivate('listActions') - def listActions(self, info): - """ - List actions available from this tool - """ - if info.isAnonymous: - return None - else: - actions = [] - folder_url = info.folder_url - content_url = info.content_url - if folder_url is not None: - actions.append( - { 'name' : 'Folder contents' - , 'url' : folder_url + '/folder_contents' - , 'permissions' : ['List folder contents'] - , 'category' : 'folder' - }) - return actions - security.declareProtected( CMFCorePermissions.ManagePortal , 'deleteActionProvider' ) @@ -162,16 +177,24 @@ break else: folder = aq_parent(aq_inner(folder)) - - info = ActionInformation(self, folder, object) - + ec = createExprContext(folder, portal, object) + ai_objs = [] actions = [] + info = oai(self, folder, object) # Include actions from specific tools. for provider_name in self.listActionProviders(): provider = getattr(self, provider_name) a = provider.listActions(info) - if a: - actions.extend(list(a)) + #import pdb; pdb.set_trace() + if a and type(a[0]) is not {}: + ai_objs.extend(list(a)) + elif len(a) > 0: + actions.append(a) + + if ai_objs: + for ai in ai_objs: + if ai.testCondition(ec): + actions.append(ai.getAction(ec)) # Include actions from object. if object is not None: @@ -181,7 +204,7 @@ if ti is not None: defs = ti.getActions() if defs: - c_url = info.content_url + c_url = object.absolute_url() for d in defs: a = d['action'] if a: @@ -197,7 +220,7 @@ 'visible': d.get('visible', 1), }) if hasattr(base, 'listActions'): - a = object.listActions(info) + a = object.listActions() if a: actions.extend(list(a)) === CMF/CMFCore/CatalogTool.py 1.21 => 1.21.14.1 === security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ZCatalog.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + ZCatalog.manage_options + )) def __init__(self): ZCatalog.__init__(self, self.getId()) === CMF/CMFCore/MemberDataTool.py 1.12 => 1.12.14.1 === from CMFCorePermissions import ViewManagementScreens import CMFCorePermissions +from ActionProviderBase import ActionProviderBase _marker = [] # Create a new marker object. -class MemberDataTool (UniqueObject, SimpleItem, PropertyManager): +class MemberDataTool (UniqueObject, SimpleItem, PropertyManager, ActionProviderBase): '''This tool wraps user objects, making them act as Member objects. ''' id = 'portal_memberdata' meta_type = 'CMF Member Data Tool' + _actions = [] _v_temps = None _properties = () security = ClassSecurityInfo() - manage_options=( ( { 'label' : 'Overview' + manage_options=( ActionProviderBase.manage_options + + ({ 'label' : 'Overview' , 'action' : 'manage_overview' } , { 'label' : 'Contents' @@ -83,8 +86,11 @@ # 'portal_memberdata' interface methods # security.declarePrivate('listActions') - def listActions(self, info): - return None + def listActions(self, info=None): + """ + Return actions provided via tool. + """ + return self._actions security.declarePrivate('getMemberDataContents') def getMemberDataContents(self): === CMF/CMFCore/MembershipTool.py 1.16 => 1.16.14.1 === from CMFCorePermissions import ManagePortal import CMFCorePermissions +from ActionProviderBase import ActionProviderBase import Acquisition default_member_content = '''Default page for %s @@ -37,22 +38,23 @@ in the Tool Box on the left. ''' -class MembershipTool (UniqueObject, SimpleItem): +class MembershipTool (UniqueObject, SimpleItem, ActionProviderBase): # This tool accesses member data through an acl_users object. # It can be replaced with something that accesses member data in # a different way. id = 'portal_membership' meta_type = 'CMF Membership Tool' - + _actions = [] security = ClassSecurityInfo() - manage_options=( { 'label' : 'Overview' - , 'action' : 'manage_overview' - } - , { 'label' : 'Configuration' + manage_options=( ({ 'label' : 'Configuration' , 'action' : 'manage_mapRoles' - } - ) + SimpleItem.manage_options + },) + + ActionProviderBase.manage_options + + ( { 'label' : 'Overview' + , 'action' : 'manage_overview' + }, + ) + SimpleItem.manage_options) # # ZMI methods @@ -387,7 +389,7 @@ security.declarePrivate('listActions') - def listActions(self, info): + def listActions(self): return None security.declarePublic('getHomeFolder') === CMF/CMFCore/PortalFolder.py 1.28 => 1.28.10.1 === , 'category' : 'folder' } - , { 'id' : 'syndication' - , 'name' : 'Syndication' - , 'action' : 'synPropertiesForm' - , 'permissions' : (ManageProperties,) - , 'category' : 'folder' - } ) } , === CMF/CMFCore/RegistrationTool.py 1.7 => 1.7.14.1 === import CMFCorePermissions import string, random +from ActionProviderBase import ActionProviderBase -class RegistrationTool (UniqueObject, SimpleItem): +class RegistrationTool (UniqueObject, SimpleItem, ActionProviderBase): # This tool creates and modifies users by making calls # to portal_membership. id = 'portal_registration' @@ -37,9 +38,10 @@ security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = (ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + SimpleItem.manage_options + ) + SimpleItem.manage_options) # # ZMI methods @@ -51,9 +53,6 @@ # # 'portal_registration' interface methods # - security.declarePrivate('listActions') - def listActions(self, info): - return none security.declarePublic('isRegistrationAllowed') def isRegistrationAllowed(self, REQUEST): === CMF/CMFCore/SkinsTool.py 1.11 => 1.11.14.1 === security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( modifiedOptions() + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + modifiedOptions() + )) def __init__(self): self.selections = PersistentMapping() === CMF/CMFCore/TypesTool.py 1.26 => 1.26.14.1 === security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( OFS.Folder.Folder.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + OFS.Folder.Folder.manage_options + )) # # ZMI methods === CMF/CMFCore/UndoTool.py 1.4 => 1.4.14.1 === from string import split from AccessControl import ClassSecurityInfo - +from Expression import Expression +from ActionInformation import ActionInformation +from ActionProviderBase import ActionProviderBase from CMFCorePermissions import ManagePortal, UndoChanges, ListUndoableChanges -class UndoTool (UniqueObject, SimpleItem): +class UndoTool (UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_undo' meta_type = 'CMF Undo Tool' # This tool is used to undo changes. + _actions = [ActionInformation(id='undo' + , title='Undo' + , action=Expression( + text='string: ${portal_url}/undo_form') + , condition=Expression( + text='member') + , permissions=(ListUndoableChanges,) + , category='global' + , visible=1 + )] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ActionProviderBase.manage_options + + SimpleItem.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + SimpleItem.manage_options - + )) # # ZMI methods # @@ -46,14 +59,11 @@ manage_overview = DTMLFile( 'explainUndoTool', _dtmldir ) security.declarePrivate('listActions') - def listActions( self, info ): - if info.isAnonymous: - return [] - return [ { 'name': 'Undo' - , 'url': 'undo_form' - , 'permissions': [ ListUndoableChanges ] - , 'category': 'global' - } ] + def listActions(self, info=None): + """ + List actions available through tool + """ + return self._actions # # 'portal_undo' interface methods === CMF/CMFCore/WorkflowTool.py 1.19 => 1.19.4.1 === security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } - , { 'label' : 'Workflows' + manage_options = ( { 'label' : 'Workflows' , 'action' : 'manage_selectWorkflows' } + , { 'label' : 'Overview', 'action' : 'manage_overview' } ) + Folder.manage_options # From andrew@zope.com Thu Jan 3 00:13:56 2002 From: andrew@zope.com (Andrew Sawyers) Date: Wed, 2 Jan 2002 19:13:56 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.1.2.2 ActionProviderBase.py:1.1.2.2 ActionsTool.py:1.19.10.2 Message-ID: <200201030013.g030Dub01908@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv1238/CMFCore Modified Files: Tag: andrew_ttw_actions-branch ActionInformation.py ActionProviderBase.py ActionsTool.py Log Message: *Cleanup of changeActions in ActionProviderbase *Removed tools from action_providers which do not have any default actions *Moved Join action to Registration Tool *Moved Reconfigure Portal to ProtertiesTool === CMF/CMFCore/ActionInformation.py 1.1.2.1 => 1.1.2.2 === is visible in the UI """ - if self.visible: - return self.visible - else: - return 1 + return self.visible security.declarePublic('getPriority') def getPriority(self): === CMF/CMFCore/ActionProviderBase.py 1.1.2.1 => 1.1.2.2 === else: a1['permission'] = '' - if not a.getCategory(): - a1['category'] = 'object' - else: - a1['category'] = a.getCategory() - if not a.getVisibility(): - a1['visible'] = 1 - else: - a1['visible'] = a.getVisibility() + a1['category'] = a.getCategory() or 'object' + a1['visible'] = a.getVisibility() if a._action: a1['action'] = a._action.text else: @@ -145,7 +139,7 @@ 'permissions': (properties.get('permission_' + s_idx, ()),), 'category': str(properties.get('category_' + s_idx, 'object')), - 'visible': not not properties.get('visible_' + s_idx, 0), + 'visible': properties.get('visible_' + s_idx, 0), } if not action['name']: raise ValueError('A name is required.') @@ -156,11 +150,10 @@ a._action = Expression(text=action['action']) else: a._action.text = action['action'] - if not a.condition: + if action['condition'] is not '': a.condition = Expression(text=action['condition']) else: - del(a.condition) - a.condition= Expression(text = action['condition']) + a.condition = '' a.permissions = action['permissions'] a.category = action['category'] a.visible = action['visible'] === CMF/CMFCore/ActionsTool.py 1.19.10.1 => 1.19.10.2 === action_providers = ('portal_membership' - , 'portal_memberdata' , 'portal_actions' , 'portal_registration' , 'portal_discussion' , 'portal_undo' , 'portal_syndication' - , 'portal_workflow') + , 'portal_workflow' + , 'portal_properties') security = ClassSecurityInfo() From andrew@zope.com Thu Jan 3 00:13:56 2002 From: andrew@zope.com (Andrew Sawyers) Date: Wed, 2 Jan 2002 19:13:56 -0500 Subject: [CMF-checkins] CVS: CMF/CMFDefault - MembershipTool.py:1.17.12.2 PropertiesTool.py:1.5.12.1 RegistrationTool.py:1.8.8.2 Message-ID: <200201030013.g030Dud01912@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFDefault In directory cvs.zope.org:/tmp/cvs-serv1238/CMFDefault Modified Files: Tag: andrew_ttw_actions-branch MembershipTool.py PropertiesTool.py RegistrationTool.py Log Message: *Cleanup of changeActions in ActionProviderbase *Removed tools from action_providers which do not have any default actions *Moved Join action to Registration Tool *Moved Reconfigure Portal to ProtertiesTool === CMF/CMFDefault/MembershipTool.py 1.17.12.1 => 1.17.12.2 === """ """ - _actions =[ActionInformation(id='join' - , title='Join' - , description='Click here to Join' - , action=Expression( - text='string: ${portal_url}/join_form') - , permissions=(View,) - , category='user' - , condition=Expression(text='not: member') - , visible=1 - ) - , ActionInformation(id='login' + _actions =[ActionInformation(id='login' , title='Login' , description='Click here to Login' , action=Expression( @@ -83,16 +73,6 @@ , permissions=(View,) , category='user' , condition=Expression(text='member') - , visible=1 - ) - , ActionInformation(id='configPortal' - , title='Reconfigure Portal' - , description='Reconfigure the portal' - , action=Expression( - text='string: ${portal_url}/reconfig_form') - , permissions=(ManagePortal,) - , category='global' - , condition=None , visible=1 ) , ActionInformation(id='addFavorite' === CMF/CMFDefault/PropertiesTool.py 1.5 => 1.5.12.1 === from Globals import InitializeClass, DTMLFile from AccessControl import ClassSecurityInfo +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression from Products.CMFCore import CMFCorePermissions from utils import _dtmldir -class PropertiesTool (UniqueObject, SimpleItem): +class PropertiesTool(UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_properties' meta_type = 'Default Properties Tool' + _actions = [ActionInformation(id='configPortal' + , title='Reconfigure Portal' + , description='Reconfigure the portal' + , action=Expression( + text='string: ${portal_url}/reconfig_form') + , permissions=(CMFCorePermissions.ManagePortal,) + , category='global' + , condition=None + , visible=1 + )] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , ) + SimpleItem.manage_options + ) # # ZMI methods @@ -48,6 +63,13 @@ # # 'portal_properties' interface methods # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return actions provided by tool. + """ + return self._actions + security.declareProtected( CMFCorePermissions.ManagePortal , 'editProperties' ) def editProperties(self, props): === CMF/CMFDefault/RegistrationTool.py 1.8.8.1 => 1.8.8.2 === from Products.CMFCore.utils import UniqueObject from Products.CMFCore.utils import _checkPermission, getToolByName +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression from Products.CMFCore.ActionProviderBase import ActionProviderBase from Products.CMFCore.RegistrationTool import RegistrationTool @@ -31,7 +33,16 @@ class RegistrationTool (RegistrationTool, ActionProviderBase): meta_type = 'Default Registration Tool' - _actions = [] + _actions = [ActionInformation(id='join' + , title='Join' + , description='Click here to Join' + , action=Expression( + text='string: ${portal_url}/join_form') + , permissions=(CMFCorePermissions.View,) + , category='user' + , condition=Expression(text='not: member') + , visible=1 + )] security = ClassSecurityInfo() From andrew@zope.com Thu Jan 3 15:07:54 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 10:07:54 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionProviderBase.py:1.1.2.3 ActionsTool.py:1.19.10.3 SkinsTool.py:1.11.14.2 Message-ID: <200201031507.g03F7sa20162@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv19741/CMFCore Modified Files: Tag: andrew_ttw_actions-branch ActionProviderBase.py ActionsTool.py SkinsTool.py Log Message: *Various logic and bug fixes to ActionsTool and ActionProviderBase *Added TTW Action support to SkinsTool and URLTool === CMF/CMFCore/ActionProviderBase.py 1.1.2.2 => 1.1.2.3 === a.id = action['id'] a.title = action['name'] - if not a._action: + if action['action'] is not '': a._action = Expression(text=action['action']) + #if not a._action: + # a._action = Expression(text=action['action']) else: - a._action.text = action['action'] + a._action = '' if action['condition'] is not '': a.condition = Expression(text=action['condition']) else: === CMF/CMFCore/ActionsTool.py 1.19.10.2 => 1.19.10.3 === """ #import pdb; pdb.set_trace() - providers = self.listActionProviders() + providers = list(self.listActionProviders()) new_providers = [] if add_provider: providers.append(apname) @@ -186,10 +186,11 @@ provider = getattr(self, provider_name) a = provider.listActions(info) #import pdb; pdb.set_trace() - if a and type(a[0]) is not {}: + if a and type(a[0]) is not type({}): ai_objs.extend(list(a)) - elif len(a) > 0: - actions.append(a) + else: + for i in a: + actions.append(i) if ai_objs: for ai in ai_objs: === CMF/CMFCore/SkinsTool.py 1.11.14.1 => 1.11.14.2 === from AccessControl import ClassSecurityInfo from CMFCorePermissions import ManagePortal, AccessContentsInformation +from ActionProviderBase import ActionProviderBase +from ActionInformation import ActionInformation +from Expression import Expression from OFS.Image import Image from OFS.DTMLMethod import DTMLMethod @@ -53,13 +56,14 @@ 'action':'manage_propertiesForm'}] return tuple(rval) -class SkinsTool(UniqueObject, SkinsContainer, PortalFolder): +class SkinsTool(UniqueObject, SkinsContainer, PortalFolder, ActionProviderBase): ''' This tool is used to supply skins to a portal. ''' id = 'portal_skins' meta_type = 'CMF Skins Tool' + _actions = [] cookie_persistence = 0 security = ClassSecurityInfo() @@ -67,7 +71,8 @@ manage_options = ( modifiedOptions() + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - )) + ) + ActionProviderBase.manage_options + ) def __init__(self): self.selections = PersistentMapping() @@ -90,6 +95,14 @@ request_varname = 'portal_skin' allow_any = 0 selections = None + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of actions information instances + provided by the tool. + """ + return self._actions security.declareProtected(ManagePortal, 'manage_propertiesForm') manage_propertiesForm = DTMLFile('dtml/skinProps', globals()) From andrew@zope.com Thu Jan 3 15:07:54 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 10:07:54 -0500 Subject: [CMF-checkins] CVS: CMF/CMFDefault - URLTool.py:1.7.12.2 Message-ID: <200201031507.g03F7sc20163@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFDefault In directory cvs.zope.org:/tmp/cvs-serv19741/CMFDefault Modified Files: Tag: andrew_ttw_actions-branch URLTool.py Log Message: *Various logic and bug fixes to ActionsTool and ActionProviderBase *Added TTW Action support to SkinsTool and URLTool === CMF/CMFDefault/URLTool.py 1.7.12.1 => 1.7.12.2 === from Globals import InitializeClass, DTMLFile from AccessControl import ClassSecurityInfo +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression from Products.CMFCore import CMFCorePermissions from utils import _dtmldir -class URLTool (UniqueObject, SimpleItem): +class URLTool (UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_url' meta_type = 'Default URL Tool' + _actions = [] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , ) + SimpleItem.manage_options + ) # # ZMI methods @@ -55,6 +61,13 @@ Returns the absolute URL of the portal. ''' return aq_parent(aq_inner(self)).absolute_url(relative=relative) + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of actions provided via the tool + """ + return self._actions security.declarePublic( 'getPortalObject' ) def getPortalObject( self ): From andrew@zope.com Thu Jan 3 19:09:29 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 14:09:29 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.1.2.3 Expression.py:1.1.2.2 Message-ID: <200201031909.g03J9T112935@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv11908/CMFCore Modified Files: Tag: andrew_ttw_actions-branch ActionInformation.py Expression.py Log Message: *Added new method getActionExpression to return the text attribute of an action. *Removed kruft from expression context. *Added start of unit tests === CMF/CMFCore/ActionInformation.py 1.1.2.2 => 1.1.2.3 === return action + security.declarePublic('getActionExpression') + def getActionExpression(self): + """ + If not an empty string or None, return the + text of the expression otherwise return '' + """ + if self._action: + return self._action.text + else: + return self._action + security.declarePublic('getCondition') def getCondition(self): """ - If not an empty string or None, evaluate the expression + If not an empty string or None, return the + text of the expression otherwise + return '' """ if self.condition: return self.condition.text === CMF/CMFCore/Expression.py 1.1.2.1 => 1.1.2.2 === 'portal_url': portal.absolute_url(), 'object': object, - 'content': object, 'folder': folder, 'portal': portal, 'nothing': None, From andrew@zope.com Thu Jan 3 19:09:29 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 14:09:29 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/tests - test_ActionsTool.py:1.1.2.1 test_all.py:1.6.14.1 Message-ID: <200201031909.g03J9Tm12938@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/tests In directory cvs.zope.org:/tmp/cvs-serv11908/CMFCore/tests Modified Files: Tag: andrew_ttw_actions-branch test_all.py Added Files: Tag: andrew_ttw_actions-branch test_ActionsTool.py Log Message: *Added new method getActionExpression to return the text attribute of an action. *Removed kruft from expression context. *Added start of unit tests === Added File CMF/CMFCore/tests/test_ActionsTool.py === import Zope import unittest import OFS.Folder, OFS.SimpleItem import Acquisition from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import noSecurityManager from AccessControl import SecurityManager from Products.CMFCore.ActionsTool import * from Products.CMFCore.ActionInformation import ActionInformation from Products.CMFCore.Expression import Expression from Products.CMFCore.PortalContent import PortalContent from Products.CMFCore.CMFCorePermissions import AddPortalContent, ManagePortal from Products.CMFCore.CMFCorePermissions import ModifyPortalContent from Products.CMFCore import utils import ZPublisher.HTTPRequest class PermissiveSecurityPolicy: """ Stub out the existing security policy for unit testing purposes. """ # # Standard SecurityPolicy interface # def validate( self , accessed=None , container=None , name=None , value=None , context=None , roles=None , *args , **kw): return 1 def checkPermission( self, permission, object, context) : if permission == 'forbidden permission': return 0 return 1 class OmnipotentUser( Acquisition.Implicit ): """ Stubbed out manager for unit testing purposes. """ def getId( self ): return 'all_powerful_Oz' getUserName = getId def allowed( self, object, object_roles=None ): return 1 class UserWithRoles( Acquisition.Implicit ): """ Stubbed out manager for unit testing purposes. """ def __init__( self, *roles ): self._roles = roles def getId( self ): return 'high_roller' getUserName = getId def allowed( self, object, object_roles=None ): for orole in object_roles: if orole in self._roles: return 1 return 0 class UnitTestUser( Acquisition.Implicit ): """ Stubbed out manager for unit testing purposes. """ def getId( self ): return 'unit_tester' getUserName = getId def allowed( self, object, object_roles=None ): # for testing permissions on actions if object.getId() == 'actions_dummy': if 'Anonymous' in object_roles: return 1 else: return 0 return 1 class ActionsToolTests( unittest.TestCase ): def setUp( self ): get_transaction().begin() self._policy = PermissiveSecurityPolicy() self._oldPolicy = SecurityManager.setSecurityPolicy(self._policy) self.connection = Zope.DB.open() root = self.root = self.connection.root()[ 'Application' ] newSecurityManager( None, UnitTestUser().__of__( self.root ) ) env = { 'SERVER_NAME' : 'http://localhost' , 'SERVER_PORT' : '80' } root.REQUEST = ZPublisher.HTTPRequest.HTTPRequest( None, env, None ) root._setObject( 'portal_actions', ActionsTool() ) tool = root.portal_actions tool.action_providers = ('portal_actions') self.assertEqual(tool.listActionProviders(), ('portal_actions',)) def tearDown( self ): get_transaction().abort() self.connection.close() noSecurityManager() SecurityManager.setSecurityPolicy(self._oldPolicy) class ActionInformationTests(unittest.TestCase): def test_basic_construction(self): ai = ActionInformation(id='view' ) self.assertEqual(ai.getId(), 'view') self.assertEqual(ai.Title(), 'view') self.assertEqual(ai.Description(), '') self.assertEqual(ai.getCondition(), '') self.assertEqual(ai.getActionExpression(), '') self.assertEqual(ai.getPermissions(), ()) def test_construction_with_Expressions(self): ai = ActionInformation(id='view' , title='View' , action=Expression( text='view') , condition=Expression( text='member')) self.assertEqual(ai.getId(), 'view') self.assertEqual(ai.Title(), 'View') self.assertEqual(ai.Description(), '') self.assertEqual(ai.getCondition(), 'member') self.assertEqual(ai.getActionExpression(), 'view') self.assertEqual(ai.getPermissions(), ()) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ActionsToolTests)) suite.addTest(unittest.makeSuite(ActionInformationTests)) return suite def run(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': run() === CMF/CMFCore/tests/test_all.py 1.6 => 1.6.14.1 === from Products.CMFCore.tests import test_PortalFolder from Products.CMFCore.tests import test_TypesTool +from Products.CMFCore.tests import test_ActionsTool from Products.CMFCore.tests import test_CatalogTool def test_suite(): @@ -10,6 +11,7 @@ suite.addTest( test_ContentTypeRegistry.test_suite() ) suite.addTest( test_PortalFolder.test_suite() ) suite.addTest( test_TypesTool.test_suite() ) + suite.addTest( test_ActionsTool.test_suite() ) suite.addTest( test_CatalogTool.test_suite() ) return suite From andrew@zope.com Thu Jan 3 19:46:09 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 14:46:09 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionProviderBase.py:1.1.2.4 CatalogTool.py:1.21.14.2 TypesTool.py:1.26.14.2 Message-ID: <200201031946.g03Jk9U21846@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv21742/CMFCore Modified Files: Tag: andrew_ttw_actions-branch ActionProviderBase.py CatalogTool.py TypesTool.py Log Message: *changed ActionProviderBase to use getActionExpression method *Added TTW action support to CatalogTool and TypesTool which had been overlooked. === CMF/CMFCore/ActionProviderBase.py 1.1.2.3 => 1.1.2.4 === a1['visible'] = a.getVisibility() if a._action: - a1['action'] = a._action.text + a1['action'] = a.getActionExpression() else: a1['action'] = '' if a.condition: @@ -148,8 +148,6 @@ a.title = action['name'] if action['action'] is not '': a._action = Expression(text=action['action']) - #if not a._action: - # a._action = Expression(text=action['action']) else: a._action = '' if action['condition'] is not '': === CMF/CMFCore/CatalogTool.py 1.21.14.1 => 1.21.14.2 === from AccessControl import ClassSecurityInfo from utils import mergedLocalRoles +from ActionProviderBase import ActionProviderBase +from ActionInformation import ActionInformation +from Expression import Expression import os import CMFCorePermissions from Acquisition import aq_base @@ -64,14 +67,16 @@ return list(allowed.keys()) -class CatalogTool (UniqueObject, ZCatalog): +class CatalogTool (UniqueObject, ZCatalog, ActionProviderBase): '''This is a ZCatalog that filters catalog queries. ''' id = 'portal_catalog' meta_type = 'CMF Catalog' security = ClassSecurityInfo() + _actions = [] manage_options = ( ZCatalog.manage_options + + ActionProviderBase.manage_options + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , )) @@ -83,6 +88,14 @@ # # Subclass extension interface # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of action information instances + provided via tool + """ + return self._actions + security.declarePublic( 'enumerateIndexes' ) # Subclass can call def enumerateIndexes( self ): # Return a list of ( index_name, type ) pairs for the initial === CMF/CMFCore/TypesTool.py 1.26.14.1 => 1.26.14.2 === from Acquisition import aq_base import Products, CMFCorePermissions +from ActionProviderBase import ActionProviderBase +from ActionInformation import ActionInformation +from Expression import Expression from CMFCorePermissions import View, ManagePortal, AccessContentsInformation @@ -501,16 +504,18 @@ , ScriptableTypeInformation.meta_type ) -class TypesTool( UniqueObject, OFS.Folder.Folder ): +class TypesTool( UniqueObject, OFS.Folder.Folder, ActionProviderBase ): """ Provides a configurable registry of portal content types. """ id = 'portal_types' meta_type = 'CMF Types Tool' + _actions = [] security = ClassSecurityInfo() manage_options = ( OFS.Folder.Folder.manage_options + + ActionProviderBase.manage_options + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , )) @@ -521,6 +526,14 @@ security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) manage_overview = DTMLFile( 'explainTypesTool', _dtmldir ) + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of action information instances + for actions provided via tool + """ + return self._actions def all_meta_types(self): all = TypesTool.inheritedAttribute('all_meta_types')(self) From andrew@zope.com Thu Jan 3 20:38:18 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 15:38:18 -0500 Subject: [CMF-checkins] CVS: CMF/CMFDefault - MembershipTool.py:1.17.12.3 Message-ID: <200201032038.g03KcIV01414@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFDefault In directory cvs.zope.org:/tmp/cvs-serv1310/CMFDefault Modified Files: Tag: andrew_ttw_actions-branch MembershipTool.py Log Message: *Fixed a couple action expression errors. === CMF/CMFDefault/MembershipTool.py 1.17.12.2 => 1.17.12.3 === , title='my stuff' , description='Goto your home folder' - , action=Expression(text='member/getHomeUrl') + , action=Expression( + text='python: portal.portal_membership.getHomeUrl()') , permissions=(View,) , category='user' , condition=Expression( @@ -100,7 +101,7 @@ , title='My favorites' , description='Browser your favorites' , action=Expression( - text='python: member.getHomeUrl() + \'/Favorites/folder_contents\'') + text='python: portal.portal_membership.getHomeUrl() + \'/Favorites/folder_contents\'') , permissions=(View,) , category='user' , condition=Expression( From andrew@zope.com Thu Jan 3 22:43:18 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 17:43:18 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/interfaces - portal_actions.py:1.6.14.1 Message-ID: <200201032243.g03MhIr32610@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/interfaces In directory cvs.zope.org:/tmp/cvs-serv32579/CMFCore/interfaces Modified Files: Tag: andrew_ttw_actions-branch portal_actions.py Log Message: *Factored out ActionInformation tests from ActionTool tests *Fixed bug in ActionTool tests *updated test_all.py === CMF/CMFCore/interfaces/portal_actions.py 1.6 => 1.6.14.1 === # listActions__roles__ = () # No permission. def listActions(info): - '''Returns a list of mappings describing actions. Each action + '''Support for the old list of mappings is currently supported: + Returns a list of mappings describing actions. Each action should contain the keys "name", "url", "permissions", and "category", conforming to the specs outlined in portal_actions.listFilteredActionsFor(). The info argument @@ -85,5 +86,6 @@ folder_url content content_url + The new way of doing this is.... ''' From andrew@zope.com Thu Jan 3 22:43:18 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 17:43:18 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/tests - test_ActionInformation.py:1.1.2.1 test_ActionsTool.py:1.1.2.2 test_all.py:1.6.14.2 Message-ID: <200201032243.g03MhIw32614@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/tests In directory cvs.zope.org:/tmp/cvs-serv32579/CMFCore/tests Modified Files: Tag: andrew_ttw_actions-branch test_ActionsTool.py test_all.py Added Files: Tag: andrew_ttw_actions-branch test_ActionInformation.py Log Message: *Factored out ActionInformation tests from ActionTool tests *Fixed bug in ActionTool tests *updated test_all.py === Added File CMF/CMFCore/tests/test_ActionInformation.py === import unittest from Products.CMFCore.ActionsTool import * from Products.CMFCore.ActionInformation import ActionInformation from Products.CMFCore.Expression import Expression class ActionInformationTests(unittest.TestCase): def test_basic_construction(self): ai = ActionInformation(id='view' ) self.assertEqual(ai.getId(), 'view') self.assertEqual(ai.Title(), 'view') self.assertEqual(ai.Description(), '') self.assertEqual(ai.getCondition(), '') self.assertEqual(ai.getActionExpression(), '') self.assertEqual(ai.getPermissions(), ()) def test_construction_with_Expressions(self): ai = ActionInformation(id='view' , title='View' , action=Expression( text='view') , condition=Expression( text='member')) self.assertEqual(ai.getId(), 'view') self.assertEqual(ai.Title(), 'View') self.assertEqual(ai.Description(), '') self.assertEqual(ai.getCondition(), 'member') self.assertEqual(ai.getActionExpression(), 'view') self.assertEqual(ai.getPermissions(), ()) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ActionInformationTests)) return suite def run(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': run() === CMF/CMFCore/tests/test_ActionsTool.py 1.1.2.1 => 1.1.2.2 === from AccessControl import SecurityManager from Products.CMFCore.ActionsTool import * -from Products.CMFCore.ActionInformation import ActionInformation -from Products.CMFCore.Expression import Expression -from Products.CMFCore.PortalContent import PortalContent -from Products.CMFCore.CMFCorePermissions import AddPortalContent, ManagePortal +from Products.CMFCore.CMFCorePermissions import AddPortalContent from Products.CMFCore.CMFCorePermissions import ModifyPortalContent from Products.CMFCore import utils import ZPublisher.HTTPRequest @@ -37,36 +34,6 @@ return 0 return 1 -class OmnipotentUser( Acquisition.Implicit ): - """ - Stubbed out manager for unit testing purposes. - """ - def getId( self ): - return 'all_powerful_Oz' - - getUserName = getId - - def allowed( self, object, object_roles=None ): - return 1 - -class UserWithRoles( Acquisition.Implicit ): - """ - Stubbed out manager for unit testing purposes. - """ - def __init__( self, *roles ): - self._roles = roles - - def getId( self ): - return 'high_roller' - - getUserName = getId - - def allowed( self, object, object_roles=None ): - for orole in object_roles: - if orole in self._roles: - return 1 - return 0 - class UnitTestUser( Acquisition.Implicit ): """ Stubbed out manager for unit testing purposes. @@ -101,8 +68,11 @@ root.REQUEST = ZPublisher.HTTPRequest.HTTPRequest( None, env, None ) root._setObject( 'portal_actions', ActionsTool() ) - tool = root.portal_actions - tool.action_providers = ('portal_actions') + self.tool = tool = root.portal_actions + tool.action_providers = ('portal_actions',) + + def test_actionProviders(self): + tool = self.tool self.assertEqual(tool.listActionProviders(), ('portal_actions',)) def tearDown( self ): @@ -111,37 +81,9 @@ noSecurityManager() SecurityManager.setSecurityPolicy(self._oldPolicy) -class ActionInformationTests(unittest.TestCase): - - def test_basic_construction(self): - ai = ActionInformation(id='view' - ) - self.assertEqual(ai.getId(), 'view') - self.assertEqual(ai.Title(), 'view') - self.assertEqual(ai.Description(), '') - self.assertEqual(ai.getCondition(), '') - self.assertEqual(ai.getActionExpression(), '') - self.assertEqual(ai.getPermissions(), ()) - - def test_construction_with_Expressions(self): - ai = ActionInformation(id='view' - , title='View' - , action=Expression( - text='view') - , condition=Expression( - text='member')) - self.assertEqual(ai.getId(), 'view') - self.assertEqual(ai.Title(), 'View') - self.assertEqual(ai.Description(), '') - self.assertEqual(ai.getCondition(), 'member') - self.assertEqual(ai.getActionExpression(), 'view') - self.assertEqual(ai.getPermissions(), ()) - - def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ActionsToolTests)) - suite.addTest(unittest.makeSuite(ActionInformationTests)) return suite def run(): === CMF/CMFCore/tests/test_all.py 1.6.14.1 => 1.6.14.2 === from Products.CMFCore.tests import test_TypesTool from Products.CMFCore.tests import test_ActionsTool +from Products.CMFCore.tests import test_ActionInformation from Products.CMFCore.tests import test_CatalogTool def test_suite(): @@ -12,6 +13,7 @@ suite.addTest( test_PortalFolder.test_suite() ) suite.addTest( test_TypesTool.test_suite() ) suite.addTest( test_ActionsTool.test_suite() ) + suite.addTest( test_ActionInformation.test_suite() ) suite.addTest( test_CatalogTool.test_suite() ) return suite From andrew@zope.com Thu Jan 3 22:43:48 2002 From: andrew@zope.com (Andrew Sawyers) Date: Thu, 3 Jan 2002 17:43:48 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionsTool.py:1.19.10.4 Message-ID: <200201032243.g03MhmE00608@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv32579/CMFCore Modified Files: Tag: andrew_ttw_actions-branch ActionsTool.py Log Message: *Factored out ActionInformation tests from ActionTool tests *Fixed bug in ActionTool tests *updated test_all.py === CMF/CMFCore/ActionsTool.py 1.19.10.3 => 1.19.10.4 === provider = getattr(self, provider_name) a = provider.listActions(info) - #import pdb; pdb.set_trace() if a and type(a[0]) is not type({}): ai_objs.extend(list(a)) else: From andrew@zope.com Fri Jan 4 14:30:21 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 09:30:21 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionsTool.py:1.19.10.5 Message-ID: <200201041430.g04EULr31466@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv31405/CMFCore Modified Files: Tag: andrew_ttw_actions-branch ActionsTool.py Log Message: *added a few more actions tool unit tests. *removed debugging kruft from ActionsTool === CMF/CMFCore/ActionsTool.py 1.19.10.4 => 1.19.10.5 === Manage TTW Action Providers """ - #import pdb; pdb.set_trace() providers = list(self.listActionProviders()) new_providers = [] if add_provider: From andrew@zope.com Fri Jan 4 14:30:21 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 09:30:21 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/tests - test_ActionsTool.py:1.1.2.3 Message-ID: <200201041430.g04EULA31467@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/tests In directory cvs.zope.org:/tmp/cvs-serv31405/CMFCore/tests Modified Files: Tag: andrew_ttw_actions-branch test_ActionsTool.py Log Message: *added a few more actions tool unit tests. *removed debugging kruft from ActionsTool === CMF/CMFCore/tests/test_ActionsTool.py 1.1.2.2 => 1.1.2.3 === from AccessControl import SecurityManager from Products.CMFCore.ActionsTool import * +from Products.CMFDefault.URLTool import * from Products.CMFCore.CMFCorePermissions import AddPortalContent from Products.CMFCore.CMFCorePermissions import ModifyPortalContent from Products.CMFCore import utils @@ -68,12 +69,26 @@ root.REQUEST = ZPublisher.HTTPRequest.HTTPRequest( None, env, None ) root._setObject( 'portal_actions', ActionsTool() ) - self.tool = tool = root.portal_actions - tool.action_providers = ('portal_actions',) + root._setObject('foo', URLTool() ) + self.tool = root.portal_actions + self.ut = root.foo + self.tool.action_providers = ('portal_actions',) def test_actionProviders(self): tool = self.tool self.assertEqual(tool.listActionProviders(), ('portal_actions',)) + + def test_addActionProvider(self): + tool = self.tool + tool.addActionProvider('foo') + self.assertEqual(tool.listActionProviders(), + ('portal_actions', 'foo')) + + def test_delActionProvider(self): + tool = self.tool + tool.deleteActionProvider('foo') + self.assertEqual(tool.listActionProviders(), + ('portal_actions',)) def tearDown( self ): get_transaction().abort() From andrew@zope.com Fri Jan 4 17:02:37 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 12:02:37 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.1.2.4 Message-ID: <200201041702.g04H2bX04226@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv3865 Modified Files: Tag: andrew_ttw_actions-branch ActionInformation.py Log Message: *more tests *test cleanup === CMF/CMFCore/ActionInformation.py 1.1.2.3 => 1.1.2.4 === """ Return integer priority for sorting + Not used....keep and implement or toss? """ if self.priority: return self.priority From andrew@zope.com Fri Jan 4 17:02:37 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 12:02:37 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/tests - test_ActionInformation.py:1.1.2.2 test_ActionsTool.py:1.1.2.4 Message-ID: <200201041702.g04H2bS04228@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/tests In directory cvs.zope.org:/tmp/cvs-serv3865/tests Modified Files: Tag: andrew_ttw_actions-branch test_ActionInformation.py test_ActionsTool.py Log Message: *more tests *test cleanup === CMF/CMFCore/tests/test_ActionInformation.py 1.1.2.1 => 1.1.2.2 === -from Products.CMFCore.ActionsTool import * +import Zope, OFS.SimpleItem, unittest +from Products.CMFDefault.MembershipTool import * +from Products.CMFCore.PortalContent import PortalContent from Products.CMFCore.ActionInformation import ActionInformation -from Products.CMFCore.Expression import Expression +from Products.CMFCore.Expression import Expression, createExprContext + +class DummyMembershipTool: + def isAnonymousUser(self): + return 1 + +class DummyContent(PortalContent, OFS.SimpleItem.Item): + """ + """ + meta_type = 'Dummy' + url = 'foo_url' + + def __init__(self, id, url=None): + self.url = url + + def absolute_url(self): + return self.url class ActionInformationTests(unittest.TestCase): + def setUp( self ): + get_transaction().begin() + self.connection = Zope.DB.open() + root = self.root = self.connection.root()[ 'Application' ] + root._setObject('portal', DummyContent('portal', 'url_portal')) + portal = self.portal = self.root.portal + portal.portal_membership = DummyMembershipTool() + self.folder = DummyContent('foo', 'url_foo') + self.object = DummyContent('bar', 'url_bar') + def test_basic_construction(self): ai = ActionInformation(id='view' ) @@ -13,6 +40,8 @@ self.assertEqual(ai.Description(), '') self.assertEqual(ai.getCondition(), '') self.assertEqual(ai.getActionExpression(), '') + self.assertEqual(ai.getVisibility(), 1) + self.assertEqual(ai.getCategory(), 'object') self.assertEqual(ai.getPermissions(), ()) def test_construction_with_Expressions(self): @@ -21,13 +50,36 @@ , action=Expression( text='view') , condition=Expression( - text='member')) + text='member') + , category='global' + , visible=0) self.assertEqual(ai.getId(), 'view') self.assertEqual(ai.Title(), 'View') self.assertEqual(ai.Description(), '') self.assertEqual(ai.getCondition(), 'member') self.assertEqual(ai.getActionExpression(), 'view') + self.assertEqual(ai.getVisibility(), 0) + self.assertEqual(ai.getCategory(), 'global') self.assertEqual(ai.getPermissions(), ()) + + def test_Condition(self): + portal = self.portal + folder = self.folder + object = self.object + ai = ActionInformation(id='view' + , title='View' + , action=Expression( + text='view') + , condition=Expression( + text='member') + , category='global' + , visible=1) + ec = createExprContext(folder, portal, object) + self.failIf(ai.testCondition(ec)) + + def tearDown( self ): + get_transaction().abort() + self.connection.close() def test_suite(): === CMF/CMFCore/tests/test_ActionsTool.py 1.1.2.3 => 1.1.2.4 === -import unittest -import OFS.Folder, OFS.SimpleItem -import Acquisition -from AccessControl.SecurityManagement import newSecurityManager -from AccessControl.SecurityManagement import noSecurityManager -from AccessControl import SecurityManager +import Zope, unittest from Products.CMFCore.ActionsTool import * from Products.CMFDefault.URLTool import * -from Products.CMFCore.CMFCorePermissions import AddPortalContent -from Products.CMFCore.CMFCorePermissions import ModifyPortalContent -from Products.CMFCore import utils import ZPublisher.HTTPRequest -class PermissiveSecurityPolicy: - """ - Stub out the existing security policy for unit testing purposes. - """ - # - # Standard SecurityPolicy interface - # - def validate( self - , accessed=None - , container=None - , name=None - , value=None - , context=None - , roles=None - , *args - , **kw): - return 1 - - def checkPermission( self, permission, object, context) : - if permission == 'forbidden permission': - return 0 - return 1 - -class UnitTestUser( Acquisition.Implicit ): - """ - Stubbed out manager for unit testing purposes. - """ - def getId( self ): - return 'unit_tester' - - getUserName = getId - - def allowed( self, object, object_roles=None ): - # for testing permissions on actions - if object.getId() == 'actions_dummy': - if 'Anonymous' in object_roles: - return 1 - else: - return 0 - return 1 - class ActionsToolTests( unittest.TestCase ): def setUp( self ): get_transaction().begin() - self._policy = PermissiveSecurityPolicy() - self._oldPolicy = SecurityManager.setSecurityPolicy(self._policy) self.connection = Zope.DB.open() root = self.root = self.connection.root()[ 'Application' ] - newSecurityManager( None, UnitTestUser().__of__( self.root ) ) env = { 'SERVER_NAME' : 'http://localhost' , 'SERVER_PORT' : '80' @@ -93,8 +40,6 @@ def tearDown( self ): get_transaction().abort() self.connection.close() - noSecurityManager() - SecurityManager.setSecurityPolicy(self._oldPolicy) def test_suite(): suite = unittest.TestSuite() From andrew@zope.com Fri Jan 4 19:40:28 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 14:40:28 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/tests - test_Expression.py:1.1.2.1 test_all.py:1.6.14.3 Message-ID: <200201041940.g04JeSH08786@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/tests In directory cvs.zope.org:/tmp/cvs-serv8777/CMFCore/tests Modified Files: Tag: andrew_ttw_actions-branch test_all.py Added Files: Tag: andrew_ttw_actions-branch test_Expression.py Log Message: *added Expression tests === Added File CMF/CMFCore/tests/test_Expression.py === import Zope, unittest, OFS.SimpleItem, Acquisition from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import noSecurityManager from AccessControl import SecurityManager from Products.CMFCore.ActionsTool import * from Products.CMFCore.ActionInformation import ActionInformation from Products.CMFCore.PortalContent import PortalContent from Products.CMFCore.Expression import Expression, createExprContext import ZPublisher.HTTPRequest class PermissiveSecurityPolicy: """ Stub out the existing security policy for unit testing purposes. """ # # Standard SecurityPolicy interface # def validate( self , accessed=None , container=None , name=None , value=None , context=None , roles=None , *args , **kw): return 1 def checkPermission( self, permission, object, context) : if permission == 'forbidden permission': return 0 return 1 class UnitTestUser( Acquisition.Implicit ): """ Stubbed out manager for unit testing purposes. """ def getId( self ): return 'unit_tester' getUserName = getId def allowed( self, object, object_roles=None ): # for testing permissions on actions if object.getId() == 'actions_dummy': if 'Anonymous' in object_roles: return 1 else: return 0 return 1 class DummyMembershipTool: def __init__(self, anon=1): self.anon = anon def isAnonymousUser(self): return self.anon def getAuthenticatedMember(self): return "member" class DummyContent(PortalContent, OFS.SimpleItem.Item): """ """ meta_type = 'Dummy' url = 'foo_url' def __init__(self, id, url=None): self.id = id self.url = url def absolute_url(self): return self.url class ExpressionTests( unittest.TestCase ): def setUp( self ): get_transaction().begin() self._policy = PermissiveSecurityPolicy() self._oldPolicy = SecurityManager.setSecurityPolicy(self._policy) self.connection = Zope.DB.open() root = self.root = self.connection.root()[ 'Application' ] newSecurityManager(None, UnitTestUser().__of__( self.root )) root._setObject('portal', DummyContent('portal', 'url_portal')) portal = self.portal = self.root.portal self.folder = DummyContent('foo', 'url_foo') self.object = DummyContent('bar', 'url_bar') self.ai = ActionInformation(id='view' , title='View' , action=Expression( text='view') , condition=Expression( text='member') , category='global' , visible=1) def test_anonymous_ec(self): self.portal.portal_membership = DummyMembershipTool() ec = createExprContext(self.folder, self.portal, self.object) member = ec.global_vars['member'] self.failIf(member) def test_authenticatedUser_ec(self): self.portal.portal_membership = DummyMembershipTool(anon=0) ec = createExprContext(self.folder, self.portal, self.object) member = ec.global_vars['member'] self.assertEqual(member, 'member') def test_ec_context(self): self.portal.portal_membership = DummyMembershipTool() ec = createExprContext(self.folder, self.portal, self.object) object = ec.global_vars['object'] portal = ec.global_vars['portal'] folder = ec.global_vars['folder'] self.failUnless(object) self.assertEqual(object.id, 'bar') self.assertEqual(object.absolute_url(), 'url_bar') self.failUnless(portal) self.assertEqual(portal.id, 'portal') self.assertEqual(portal.absolute_url(), 'url_portal') self.failUnless(folder) self.assertEqual(folder.id, 'foo') self.assertEqual(folder.absolute_url(), 'url_foo') def tearDown( self ): get_transaction().abort() self.connection.close() noSecurityManager() SecurityManager.setSecurityPolicy(self._oldPolicy) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ExpressionTests)) return suite def run(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': run() === CMF/CMFCore/tests/test_all.py 1.6.14.2 => 1.6.14.3 === from Products.CMFCore.tests import test_ActionsTool from Products.CMFCore.tests import test_ActionInformation +from Products.CMFCore.tests import test_Expression from Products.CMFCore.tests import test_CatalogTool def test_suite(): @@ -14,6 +15,7 @@ suite.addTest( test_TypesTool.test_suite() ) suite.addTest( test_ActionsTool.test_suite() ) suite.addTest( test_ActionInformation.test_suite() ) + suite.addTest( test_Expression.test_suite() ) suite.addTest( test_CatalogTool.test_suite() ) return suite From andrew@zope.com Fri Jan 4 19:50:05 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 14:50:05 -0500 Subject: [CMF-checkins] CVS: CMF/CMFDefault - DiscussionTool.py:1.7 MembershipTool.py:1.18 MetadataTool.py:1.10 PropertiesTool.py:1.6 RegistrationTool.py:1.9 SyndicationTool.py:1.10 URLTool.py:1.8 Message-ID: <200201041950.g04Jo5511156@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFDefault In directory cvs.zope.org:/tmp/cvs-serv10417/CMFDefault Modified Files: DiscussionTool.py MembershipTool.py MetadataTool.py PropertiesTool.py RegistrationTool.py SyndicationTool.py URLTool.py Log Message: *Merging andrew_ttw_actions-branch into the head *Adds TTW configuration of Action Providers *Allows tools to have actions managed TTW *Added unittests for ActionTool, ActionInformation, and Expression *Added TTW action management to all stock CMF tools *Added Expression module for allowing actions and conditions of actions to be TALES. === CMF/CMFDefault/DiscussionTool.py 1.6 => 1.7 === from utils import _dtmldir from DiscussionItem import DiscussionItemContainer +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.Expression import Expression class DiscussionNotAllowed( Exception ): pass -class DiscussionTool( UniqueObject, SimpleItem ): +class DiscussionTool( UniqueObject, SimpleItem, ActionProviderBase ): id = 'portal_discussion' meta_type = 'Default Discussion Tool' + _actions = [ActionInformation(id='reply' + , title='Reply' + , action=Expression( + text='string: ${object_url}/discussion_reply_form') + , condition=Expression( + text='python: object is not None and ' + + 'portal.portal_discussion.isDiscussionAllowedFor(object)') + , permissions=('Reply to item',) + , category='object' + , visible=1 + )] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = (ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + SimpleItem.manage_options + ) + SimpleItem.manage_options) # # ZMI methods @@ -52,6 +67,13 @@ # 'portal_discussion' interface methods # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return available actions via tool. + """ + return self._actions + security.declarePublic( 'overrideDiscussionFor' ) def overrideDiscussionFor(self, content, allowDiscussion): """ @@ -96,29 +118,6 @@ if typeInfo: return typeInfo.allowDiscussion() return 0 - - # - # ActionProvider interface - # - security.declarePrivate( 'listActions' ) - def listActions(self, info): - # Return actions for reply and show replies - content = info.content - if content is None or not self.isDiscussionAllowedFor(content): - return None - - discussion = self.getDiscussionFor(content) - discussion_url = info.content_url - - actions = ( - {'name': 'Reply', - 'url': discussion_url + '/discussion_reply_form', - 'permissions': ['Reply to item'], - 'category': 'object' - }, - ) - - return actions # # Utility methods === CMF/CMFDefault/MembershipTool.py 1.17 => 1.18 === from Products.CMFCore.utils import _getAuthenticatedUser, _checkPermission from Products.CMFCore.utils import getToolByName +from Products.CMFCore.ActionsTool import ActionInformation import Products.CMFCore.MembershipTool from Products.CMFCore.PortalFolder import manage_addPortalFolder import Document from Globals import InitializeClass, DTMLFile from AccessControl import ClassSecurityInfo +from Products.CMFCore.Expression import Expression from Products.CMFCore.CMFCorePermissions import View, AccessContentsInformation from Products.CMFCore.CMFCorePermissions import ListPortalMembers, AddPortalMember from Products.CMFCore.CMFCorePermissions import ManagePortal @@ -40,10 +42,73 @@ in the Tool Box on the left. ''' - class MembershipTool ( Products.CMFCore.MembershipTool.MembershipTool ): """ """ + _actions =[ActionInformation(id='login' + , title='Login' + , description='Click here to Login' + , action=Expression( + text='string: ${portal_url}/login_form') + , permissions=(View,) + , category='user' + , condition=Expression(text='not: member') + , visible=1 + ) + , ActionInformation(id='preferences' + , title='Preferences' + , description='Change your user preferences' + , action=Expression( + text='string: ${portal_url}/personalize_form') + , permissions=(View,) + , category='user' + , condition=Expression(text='member') + , visible=1 + ) + , ActionInformation(id='logout' + , title='Log out' + , description='Click here to logout' + , action=Expression( + text='string: ${portal_url}/logout') + , permissions=(View,) + , category='user' + , condition=Expression(text='member') + , visible=1 + ) + , ActionInformation(id='addFavorite' + , title='Add to favorites' + , description='Add this item to your favorites' + , action=Expression( + text='string: ${portal_url}/addtoFavorites') + , permissions=(View,) + , category='user' + , condition=Expression( + text='python: portal.portal_membership.getHomeFolder()') + , visible=1 + ) + , ActionInformation(id='mystuff' + , title='my stuff' + , description='Goto your home folder' + , action=Expression( + text='python: portal.portal_membership.getHomeUrl()') + , permissions=(View,) + , category='user' + , condition=Expression( + text='python: member and portal.portal_membership.getHomeFolder()') + , visible=1 + ) + , ActionInformation(id='favorites' + , title='My favorites' + , description='Browser your favorites' + , action=Expression( + text='python: portal.portal_membership.getHomeUrl() + \'/Favorites/folder_contents\'') + , permissions=(View,) + , category='user' + , condition=Expression( + text='python: member and hasattr(portal.portal_membership.getHomeFolder(), \'Favorites\')') + , visible=1 + ) + ] meta_type = 'Default Membership Tool' @@ -151,63 +216,8 @@ return None security.declarePrivate( 'listActions' ) - def listActions(self, info): - '''Lists actions available to the user.''' - user_actions = None - portal_url = info.portal_url - if info.isAnonymous: - user_actions = ( - {'name': 'Log in', - 'url': portal_url + '/login_form', - 'permissions': [], - 'category': 'user'}, - {'name': 'Join', - 'url': portal_url + '/join_form', - 'permissions': [AddPortalMember], - 'category': 'user'}, - ) - - if not info.isAnonymous: - home_folder = self.getHomeFolder() - homeUrl = self.getHomeUrl() - user_actions = ( - {'name': 'Preferences', - 'url': portal_url + '/personalize_form', - 'permissions': [], - 'category': 'user'}, - {'name': 'Log out', - 'url': portal_url + '/logout', - 'permissions' : [], - 'category': 'user'}, - {'name': 'Reconfigure portal', - 'url': portal_url + '/reconfig_form', - 'permissions': ['Manage portal'], - 'category': 'global'}, - ) - - if homeUrl is not None: - content_url = info.content_url - actions = ( - {'name': 'Add to Favorites', - 'url': ( content_url + '/addtoFavorites' ), - 'permissions' : [], - 'category': 'user'}, - {'name': 'My Stuff', - 'url': homeUrl + '/folder_contents', - 'permissions': [], - 'category': 'user'}, - ) - user_actions = user_actions + actions - - if hasattr( home_folder, 'Favorites' ): - added_actions = ( - {'name': 'My Favorites', - 'url' : homeUrl + '/Favorites/folder_contents', - 'permissions': [], - 'category': 'user'},) - user_actions = user_actions + added_actions - - return user_actions - + def listActions(self, info=None): + '''Lists actions available through the tool.''' + return self._actions InitializeClass(MembershipTool) === CMF/CMFDefault/MetadataTool.py 1.9 => 1.10 === from AccessControl import ClassSecurityInfo, getSecurityManager from Products.CMFCore import CMFCorePermissions +from Products.CMFCore.ActionProviderBase import ActionProviderBase from utils import _dtmldir class MetadataElementPolicy( Persistent ): @@ -190,11 +191,13 @@ class MetadataError( Exception ): pass -class MetadataTool( UniqueObject, SimpleItem ): +class MetadataTool( UniqueObject, SimpleItem, ActionProviderBase ): id = 'portal_metadata' meta_type = 'Default Metadata Tool' + _actions = [] + security = ClassSecurityInfo() # @@ -225,7 +228,8 @@ # # ZMI methods # - manage_options = ( ( { 'label' : 'Overview' + manage_options = ( ActionProviderBase.manage_options + + ( { 'label' : 'Overview' , 'action' : 'manage_overview' } , { 'label' : 'Properties' @@ -248,6 +252,13 @@ security.declareProtected( CMFCorePermissions.ManagePortal , 'propertiesForm' ) propertiesForm = DTMLFile( 'metadataProperties', _dtmldir ) + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return actions provided via tool. + """ + return self._actions security.declareProtected( CMFCorePermissions.ManagePortal , 'editProperties' ) === CMF/CMFDefault/PropertiesTool.py 1.5 => 1.6 === from Globals import InitializeClass, DTMLFile from AccessControl import ClassSecurityInfo +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression from Products.CMFCore import CMFCorePermissions from utils import _dtmldir -class PropertiesTool (UniqueObject, SimpleItem): +class PropertiesTool(UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_properties' meta_type = 'Default Properties Tool' + _actions = [ActionInformation(id='configPortal' + , title='Reconfigure Portal' + , description='Reconfigure the portal' + , action=Expression( + text='string: ${portal_url}/reconfig_form') + , permissions=(CMFCorePermissions.ManagePortal,) + , category='global' + , condition=None + , visible=1 + )] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , ) + SimpleItem.manage_options + ) # # ZMI methods @@ -48,6 +63,13 @@ # # 'portal_properties' interface methods # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return actions provided by tool. + """ + return self._actions + security.declareProtected( CMFCorePermissions.ManagePortal , 'editProperties' ) def editProperties(self, props): === CMF/CMFDefault/RegistrationTool.py 1.8 => 1.9 === from Products.CMFCore.utils import UniqueObject from Products.CMFCore.utils import _checkPermission, getToolByName +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression +from Products.CMFCore.ActionProviderBase import ActionProviderBase from Products.CMFCore.RegistrationTool import RegistrationTool from Globals import InitializeClass, DTMLFile @@ -27,9 +30,20 @@ from Products.CMFCore import CMFCorePermissions from utils import _dtmldir -class RegistrationTool (RegistrationTool): +class RegistrationTool (RegistrationTool, ActionProviderBase): meta_type = 'Default Registration Tool' + _actions = [ActionInformation(id='join' + , title='Join' + , description='Click here to Join' + , action=Expression( + text='string: ${portal_url}/join_form') + , permissions=(CMFCorePermissions.View,) + , category='user' + , condition=Expression(text='not: member') + , visible=1 + )] + security = ClassSecurityInfo() # @@ -37,6 +51,11 @@ # security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) + + manage_options = ( ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } + , + )) manage_overview = DTMLFile( 'explainRegistrationTool', _dtmldir ) # @@ -55,10 +74,11 @@ return None security.declarePublic('listActions') - def listActions(self, info): + def listActions(self, info=None): """ + Return actions provided via tool. """ - return None + return self._actions security.declarePublic( 'testPropertiesValidity' ) def testPropertiesValidity(self, props, member=None): === CMF/CMFDefault/SyndicationTool.py 1.9 => 1.10 === from Products.CMFCore.CMFCorePermissions import ManageProperties from Products.CMFCore.CMFCorePermissions import AccessContentsInformation +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression import Products.CMFCore.CMFCorePermissions from Products.CMFCore.PortalFolder import PortalFolder from SyndicationInfo import SyndicationInformation _dtmldir = os.path.join( package_home( globals() ), 'dtml' ) -class SyndicationTool (UniqueObject, SimpleItem): +class SyndicationTool (UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_syndication' meta_type = 'Default Syndication Tool' + _actions = [ActionInformation(id='syndication' + , title='Syndication' + , action=Expression( + text='string: ${folder_url}/synPropertiesForm') + , condition=Expression( + text='python: folder is object') + , permissions=(ManageProperties,) + , category='folder' + , visible=1 + )] + security = ClassSecurityInfo() #Default Sitewide Values @@ -46,7 +60,8 @@ max_items = 15 #ZMI Methods - manage_options = (({'label' : 'Overview' + manage_options = (ActionProviderBase.manage_options + + ({'label' : 'Overview' ,'action' : 'overview' , 'help' : ('CMFDefault', 'Syndication-Tool_Overview.stx') } ,{'label' : 'Properties' @@ -69,6 +84,13 @@ security.declareProtected(ManagePortal, 'reportForm') reportForm = HTMLFile('synReports', _dtmldir) + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return actions provided by tool + """ + return self._actions + security.declareProtected(ManagePortal, 'editProperties') def editProperties(self , updatePeriod=None === CMF/CMFDefault/URLTool.py 1.7 => 1.8 === from Globals import InitializeClass, DTMLFile from AccessControl import ClassSecurityInfo +from Products.CMFCore.ActionProviderBase import ActionProviderBase +from Products.CMFCore.ActionInformation import ActionInformation +from Products.CMFCore.Expression import Expression from Products.CMFCore import CMFCorePermissions from utils import _dtmldir -class URLTool (UniqueObject, SimpleItem): +class URLTool (UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_url' meta_type = 'Default URL Tool' + _actions = [] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , ) + SimpleItem.manage_options + ) # # ZMI methods @@ -55,6 +61,13 @@ Returns the absolute URL of the portal. ''' return aq_parent(aq_inner(self)).absolute_url(relative=relative) + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of actions provided via the tool + """ + return self._actions security.declarePublic( 'getPortalObject' ) def getPortalObject( self ): From andrew@zope.com Fri Jan 4 19:50:35 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 14:50:35 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore - ActionInformation.py:1.2 ActionProviderBase.py:1.2 Expression.py:1.2 ActionsTool.py:1.20 CatalogTool.py:1.22 MemberDataTool.py:1.13 MembershipTool.py:1.17 PortalFolder.py:1.29 RegistrationTool.py:1.8 SkinsTool.py:1.12 TypesTool.py:1.27 UndoTool.py:1.5 WorkflowTool.py:1.20 Message-ID: <200201041950.g04JoZP11172@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore In directory cvs.zope.org:/tmp/cvs-serv10417/CMFCore Modified Files: ActionsTool.py CatalogTool.py MemberDataTool.py MembershipTool.py PortalFolder.py RegistrationTool.py SkinsTool.py TypesTool.py UndoTool.py WorkflowTool.py Added Files: ActionInformation.py ActionProviderBase.py Expression.py Log Message: *Merging andrew_ttw_actions-branch into the head *Adds TTW configuration of Action Providers *Allows tools to have actions managed TTW *Added unittests for ActionTool, ActionInformation, and Expression *Added TTW action management to all stock CMF tools *Added Expression module for allowing actions and conditions of actions to be TALES. === CMF/CMFCore/ActionInformation.py 1.1 => 1.2 === +# +# 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 +# +############################################################################## + +"""Basic action list tool. + +$Id$ +""" +__version__='$Revision$'[11:-2] + +from utils import SimpleItemWithProperties, _dtmldir, getToolByName +import CMFCorePermissions +from AccessControl import ClassSecurityInfo +from Acquisition import aq_inner, aq_parent +from Globals import InitializeClass, DTMLFile + +class ActionInformation(SimpleItemWithProperties): + """ + Represent a single action which the user can select from a list + and execut in some context. + """ + _isActionInformation = 1 + __allow_access_to_unprotected_subobjects__ = 1 + + manage_options = (SimpleItemWithProperties.manage_options[:1] + + ({'label': 'Actions', + 'action': 'manage_editActionsForm'},) + + SimpleItemWithProperties.manage_options[1:]) + security = ClassSecurityInfo() + security.declareProtected(CMFCorePermissions.ManagePortal + , 'manage_editProperties' + , 'manage_changeProperties' + , 'manage_propertiesForm' + ) + + _basic_properties = ( + {'id': 'title', 'type': 'string', 'mode': 'w', 'label': 'Title'} + , {'id': 'description', 'type': 'text', 'mode': 'w', + 'label': 'Description'} + , {'id': 'category', 'type': 'string', 'mode': 'w', + 'label': 'Category'} + , {'id': 'priority', 'type': 'boolean', 'mode': 'w', 'label': 'Priority'} + ) + + title = '' + description = '' + category = '' + priority = 0 + visible = 1 + _action = '' + + def __init__(self + , id + , title='' + , description='' + , category='object' + , condition='' + , permissions=() + , priority=10 + , visible=1 + , action=''): + """ + Setup an instance + """ + 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 + + + security.declareProtected(CMFCorePermissions.View, 'Title') + def Title(self): + """ + Return the Action title - name + """ + if self.title: + return self.title + else: + return self.getId() + + security.declareProtected(CMFCorePermissions.View, 'Description') + def Description(self): + """ + Return a description of the action + """ + return self.description + + security.declarePrivate('testCondition') + def testCondition(self, ec): + """ + Evaluate condition and return 0 or 1 + """ + if self.condition: + return self.condition(ec) + else: + return 1 + + security.declarePublic('getAction') + def getAction(self, ec): + """ + Return the action, which is an TALES expresssion + """ + if self._action: + aa = self._action(ec) + else: + aa = '' + action = {} + action['id'] = self.id + action['name'] = self.Title() + action['url'] = aa + action['permissions'] = self.getPermissions() + action['category'] = self.getCategory() + action['visible'] = self.getVisibility() + return action + + security.declarePublic('getActionExpression') + def getActionExpression(self): + """ + If not an empty string or None, return the + text of the expression otherwise return '' + """ + if self._action: + return self._action.text + else: + return self._action + + security.declarePublic('getCondition') + def getCondition(self): + """ + If not an empty string or None, return the + text of the expression otherwise + return '' + """ + if self.condition: + return self.condition.text + else: + return self.condition + + security.declarePublic('getPermission') + def getPermissions(self): + """ + Return the permission if any required for a user to + execute the action + """ + return self.permissions + + security.declarePublic('getCategory') + def getCategory(self): + """ + Return the category for which the action is + """ + if self.category: + return self.category + else: + return 'object' + + security.declarePublic('getVisibility') + def getVisibility(self): + """ + Return boolean for whether the action + is visible in the UI + """ + return self.visible + + security.declarePublic('getPriority') + def getPriority(self): + """ + Return integer priority for sorting + Not used....keep and implement or toss? + """ + if self.priority: + return self.priority + else: + return 10 + +InitializeClass(ActionInformation) + +class oai: + #Provided for backwards compatability + # Provides information that may be needed when constructing the list of + # available actions. + __allow_access_to_unprotected_subobjects__ = 1 + + def __init__(self, tool, folder, object=None): + self.portal = portal = aq_parent(aq_inner(tool)) + membership = getToolByName(tool, 'portal_membership') + self.isAnonymous = membership.isAnonymousUser() + self.portal_url = portal.absolute_url() + if folder is not None: + self.folder_url = folder.absolute_url() + self.folder = folder + else: + self.folder_url = self.portal_url + self.folder = portal + self.content = object + if object is not None: + self.content_url = object.absolute_url() + else: + self.content_url = None + + def __getitem__(self, name): + # Mapping interface for easy string formatting. + if name[:1] == '_': + raise KeyError, name + if hasattr(self, name): + return getattr(self, name) + raise KeyError, name + === CMF/CMFCore/ActionProviderBase.py 1.1 => 1.2 === +# +# 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 +# +############################################################################## + +from OFS.SimpleItem import SimpleItem +from Globals import DTMLFile +from CMFCorePermissions import ManagePortal +from utils import _dtmldir, cookString +from AccessControl import ClassSecurityInfo +from ActionInformation import ActionInformation +from Expression import Expression + + +"""Basic action list tool. + +$Id$ +""" +__version__='$Revision$'[11:-2] + +class ActionProviderBase: + """ + Provide ActionTabs and management methods for ActionProviders + """ + _actions = [] + security = ClassSecurityInfo() + _actions_form = DTMLFile( 'editToolsActions', _dtmldir ) + + manage_options = ({ 'label' : 'Actions', 'action' : 'manage_editActionsForm' } + , + ) + + security.declarePrivate('listActions') + def listActions(self): + """ + Return all the actions defined by a tool + """ + if self._actions: + return self._actions + else: + return None + + security.declareProtected(ManagePortal, 'manage_editActionsForm') + def manage_editActionsForm(self, REQUEST, manage_tabs_message=None): + """ + Shows the 'Actions' management tab. + """ + actions = [] + if self.listActions() is not None: + for a in self.listActions(): + a1 = {} + a1['id'] = a.getId() + a1['name'] = a.Title() + p = a.getPermissions() + if p: + a1['permission'] = p[0] + else: + a1['permission'] = '' + a1['category'] = a.getCategory() or 'object' + a1['visible'] = a.getVisibility() + if a._action: + a1['action'] = a.getActionExpression() + else: + a1['action'] = '' + if a.condition: + a1['condition'] = a.getCondition() + else: + a1['condition'] = '' + actions.append(a1) + # possible_permissions is in AccessControl.Role.RoleManager. + pp = self.possible_permissions() + return self._actions_form(self, REQUEST, + actions=actions, + possible_permissions=pp, + management_view='Actions', + manage_tabs_message=manage_tabs_message) + + security.declareProtected(ManagePortal, 'addAction') + def addAction( self + , id + , name + , action + , condition + , permission + , category + , visible=1 + , REQUEST=None + ): + """ + Adds an action to the list. + """ + al = self._actions + if not name: + raise ValueError('A name is required.') + if action: + a_expr = Expression(text=str(action)) + else: + a_expr = '' + if condition: + c_expr = Expression(text=str(condition)) + else: + c_expr = '' + al.append(ActionInformation(id=str(id) + , title=str(name) + , action=a_expr + , condition=c_expr + , permissions=(str(permission),) + , category=str(category) + , visible=int(visible) + )) + self._actions = al + if REQUEST is not None: + return self.manage_editActionsForm( + REQUEST, manage_tabs_message='Added.') + + security.declareProtected(ManagePortal, 'changeActions') + def changeActions(self, properties=None, REQUEST=None): + """ + Changes the _actions. + """ + if properties is None: + properties = REQUEST + actions = [] + for idx in range(len(self._actions)): + s_idx = str(idx) + action = { + 'id': str(properties.get('id_' + s_idx, '')), + 'name': str(properties.get('name_' + s_idx, '')), + 'action': str(properties.get('action_' + s_idx, '')), + 'condition': str(properties.get('condition_' + s_idx, '')), + 'permissions': + (properties.get('permission_' + s_idx, ()),), + 'category': str(properties.get('category_' + s_idx, 'object')), + 'visible': properties.get('visible_' + s_idx, 0), + } + if not action['name']: + raise ValueError('A name is required.') + a = self._actions[idx] + a.id = action['id'] + a.title = action['name'] + if action['action'] is not '': + a._action = Expression(text=action['action']) + else: + a._action = '' + if action['condition'] is not '': + a.condition = Expression(text=action['condition']) + else: + a.condition = '' + a.permissions = action['permissions'] + a.category = action['category'] + a.visible = action['visible'] + if REQUEST is not None: + return self.manage_editActionsForm(REQUEST, manage_tabs_message= + 'Actions changed.') + + security.declareProtected(ManagePortal, 'deleteActions') + def deleteActions(self, selections=(), REQUEST=None): + """ + Deletes actions. + """ + actions = list(self._actions) + sels = list(map(int, selections)) # Convert to a list of integers. + sels.sort() + sels.reverse() + for idx in sels: + del actions[idx] + self._actions = actions + if REQUEST is not None: + return self.manage_editActionsForm( + REQUEST, manage_tabs_message=( + 'Deleted %d action(s).' % len(sels))) + + security.declareProtected(ManagePortal, 'moveUpActions') + def moveUpActions(self, selections=(), REQUEST=None): + """ + Moves the specified actions up one slot. + """ + actions = list(self._actions) + sels = list(map(int, selections)) # Convert to a list of integers. + sels.sort() + for idx in sels: + idx2 = idx - 1 + if idx2 < 0: + # Wrap to the bottom. + idx2 = len(actions) - 1 + # Swap. + a = actions[idx2] + actions[idx2] = actions[idx] + actions[idx] = a + self._actions = actions + if REQUEST is not None: + return self.manage_editActionsForm( + REQUEST, manage_tabs_message=( + 'Moved up %d action(s).' % len(sels))) + + security.declareProtected(ManagePortal, 'moveDownActions') + def moveDownActions(self, selections=(), REQUEST=None): + """ + Moves the specified actions down one slot. + """ + actions = list(self._actions) + sels = list(map(int, selections)) # Convert to a list of integers. + sels.sort() + sels.reverse() + for idx in sels: + idx2 = idx + 1 + if idx2 >= len(actions): + # Wrap to the top. + idx2 = 0 + # Swap. + a = actions[idx2] + actions[idx2] = actions[idx] + actions[idx] = a + self._actions = actions + if REQUEST is not None: + return self.manage_editActionsForm( + REQUEST, manage_tabs_message=( + 'Moved down %d action(s).' % len(sels))) === CMF/CMFCore/Expression.py 1.1 => 1.2 === +# +# 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. +$Id$ +''' +__version__='$Revision$'[11:-2] + +import Globals +from Globals import Persistent +from Acquisition import aq_inner, aq_parent +from AccessControl import getSecurityManager, ClassSecurityInfo + +from utils import getToolByName +from Products.PageTemplates.Expressions import getEngine +from Products.PageTemplates.TALES import SafeMapping +from Products.PageTemplates.PageTemplate import ModuleImporter + + +class Expression (Persistent): + text = '' + _v_compiled = None + + security = ClassSecurityInfo() + + def __init__(self, text): + self.text = text + self._v_compiled = getEngine().compile(text) + + def __call__(self, econtext): + compiled = self._v_compiled + if compiled is None: + compiled = self._v_compiled = getEngine().compile(self.text) + # ?? Maybe expressions should manipulate the security + # context stack. + res = compiled(econtext) + if isinstance(res, Exception): + raise res + #print 'returning %s from %s' % (`res`, self.text) + return res + +Globals.InitializeClass(Expression) + + +def createExprContext(folder, portal, object): + ''' + An expression context provides names for TALES expressions. + ''' + pm = getToolByName(portal, 'portal_membership') + if object is None: + object_url = '' + else: + object_url = object.absolute_url() + if pm.isAnonymousUser(): + member = None + else: + member = pm.getAuthenticatedMember() + data = { + 'object_url': object_url, + 'folder_url': folder.absolute_url(), + 'portal_url': portal.absolute_url(), + 'object': object, + 'folder': folder, + 'portal': portal, + 'nothing': None, + 'request': getattr( object, 'REQUEST', None ), + 'modules': ModuleImporter, + 'member': member, + } + return getEngine().getContext(data) + === CMF/CMFCore/ActionsTool.py 1.19 => 1.20 === -from utils import UniqueObject, _getAuthenticatedUser, _checkPermission -from utils import getToolByName, _dtmldir +import OFS +from utils import UniqueObject, SimpleItemWithProperties, _getAuthenticatedUser, _checkPermission +from utils import getToolByName, _dtmldir, cookString import CMFCorePermissions from OFS.SimpleItem import SimpleItem from Globals import InitializeClass, DTMLFile, package_home @@ -27,60 +28,57 @@ from Acquisition import aq_base, aq_inner, aq_parent from AccessControl import ClassSecurityInfo from string import join +from Expression import Expression, createExprContext +from ActionInformation import ActionInformation, oai +from ActionProviderBase import ActionProviderBase -class ActionInformation: - # Provides information that may be needed when constructing the list of - # available actions. - __allow_access_to_unprotected_subobjects__ = 1 - - def __init__(self, tool, folder, object=None): - self.portal = portal = aq_parent(aq_inner(tool)) - membership = getToolByName(tool, 'portal_membership') - self.isAnonymous = membership.isAnonymousUser() - self.portal_url = portal.absolute_url() - if folder is not None: - self.folder_url = folder.absolute_url() - self.folder = folder - else: - self.folder_url = self.portal_url - self.folder = portal - self.content = object - if object is not None: - self.content_url = object.absolute_url() - else: - self.content_url = None - def __getitem__(self, name): - # Mapping interface for easy string formatting. - if name[:1] == '_': - raise KeyError, name - if hasattr(self, name): - return getattr(self, name) - raise KeyError, name - - -class ActionsTool (UniqueObject, SimpleItem): +class ActionsTool(UniqueObject, OFS.Folder.Folder, ActionProviderBase): """ Weave together the various sources of "actions" which are apropos to the current user and context. """ id = 'portal_actions' + _actions = [ActionInformation(id='folderContents' + , title='Folder contents' + , action=Expression( + text='string: ${folder_url}/folder_contents') + , condition=Expression( + text='python: folder is not object') + , permissions=('List folder contents',) + , category='object' + , visible=1 + ) + , ActionInformation(id='folderContents' + , title='Folder contents' + , action=Expression( + text='string: ${folder_url}/folder_contents') + , condition=Expression( + text='python: folder is object') + , permissions=('List folder contents',) + , category='folder' + , visible=1 + )] + meta_type = 'CMF Actions Tool' - action_providers = ( 'portal_actions' - , 'portal_memberdata' - , 'portal_registration' - , 'portal_discussion' - , 'portal_membership' - , 'portal_workflow' - , 'portal_undo' - ) + action_providers = ('portal_membership' + , 'portal_actions' + , 'portal_registration' + , 'portal_discussion' + , 'portal_undo' + , 'portal_syndication' + , 'portal_workflow' + , 'portal_properties') security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } - , - ) + SimpleItem.manage_options + manage_options = ( ActionProviderBase.manage_options + + ({'label' : 'Action Providers', 'action' : 'manage_actionProviders'} + , { 'label' : 'Overview', 'action' : 'manage_overview' } + , + ) + OFS.Folder.Folder.manage_options + ) # # ZMI methods @@ -88,19 +86,55 @@ security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) manage_overview = DTMLFile( 'explainActionsTool', _dtmldir ) + manage_actionProviders = DTMLFile('manageActionProviders', _dtmldir) # # Programmatically manipulate the list of action providers # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Lists actions available through the tool. + """ + return self._actions + security.declareProtected( CMFCorePermissions.ManagePortal , 'listActionProviders' ) - def listActionProviders( self ): + def listActionProviders(self): """ returns a sequence of action providers known by this tool """ return self.action_providers + security.declareProtected(CMFCorePermissions.ManagePortal + , 'manage_aproviders') + def manage_aproviders(self + , apname='' + , chosen=() + , add_provider=0 + , del_provider=0 + , REQUEST=None): + """ + Manage TTW Action Providers + """ + providers = list(self.listActionProviders()) + new_providers = [] + if add_provider: + providers.append(apname) + elif del_provider: + for item in providers: + if item not in chosen: + new_providers.append(item) + providers = new_providers + self.action_providers = providers + if REQUEST is not None: + return self.manage_actionProviders(self + , REQUEST + , manage_tabs_message='Properties changed.') + + + security.declareProtected( CMFCorePermissions.ManagePortal , 'addActionProvider' ) @@ -111,26 +145,6 @@ p_new = p_old + ( provider_name, ) self.action_providers = p_new - security.declarePrivate('listActions') - def listActions(self, info): - """ - List actions available from this tool - """ - if info.isAnonymous: - return None - else: - actions = [] - folder_url = info.folder_url - content_url = info.content_url - if folder_url is not None: - actions.append( - { 'name' : 'Folder contents' - , 'url' : folder_url + '/folder_contents' - , 'permissions' : ['List folder contents'] - , 'category' : 'folder' - }) - return actions - security.declareProtected( CMFCorePermissions.ManagePortal , 'deleteActionProvider' ) @@ -162,16 +176,24 @@ break else: folder = aq_parent(aq_inner(folder)) - - info = ActionInformation(self, folder, object) - + ec = createExprContext(folder, portal, object) + ai_objs = [] actions = [] + info = oai(self, folder, object) # Include actions from specific tools. for provider_name in self.listActionProviders(): provider = getattr(self, provider_name) a = provider.listActions(info) - if a: - actions.extend(list(a)) + if a and type(a[0]) is not type({}): + ai_objs.extend(list(a)) + else: + for i in a: + actions.append(i) + + if ai_objs: + for ai in ai_objs: + if ai.testCondition(ec): + actions.append(ai.getAction(ec)) # Include actions from object. if object is not None: @@ -181,7 +203,7 @@ if ti is not None: defs = ti.getActions() if defs: - c_url = info.content_url + c_url = object.absolute_url() for d in defs: a = d['action'] if a: @@ -197,7 +219,7 @@ 'visible': d.get('visible', 1), }) if hasattr(base, 'listActions'): - a = object.listActions(info) + a = object.listActions() if a: actions.extend(list(a)) === CMF/CMFCore/CatalogTool.py 1.21 => 1.22 === from AccessControl import ClassSecurityInfo from utils import mergedLocalRoles +from ActionProviderBase import ActionProviderBase +from ActionInformation import ActionInformation +from Expression import Expression import os import CMFCorePermissions from Acquisition import aq_base @@ -64,16 +67,19 @@ return list(allowed.keys()) -class CatalogTool (UniqueObject, ZCatalog): +class CatalogTool (UniqueObject, ZCatalog, ActionProviderBase): '''This is a ZCatalog that filters catalog queries. ''' id = 'portal_catalog' meta_type = 'CMF Catalog' security = ClassSecurityInfo() + _actions = [] - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ZCatalog.manage_options + + ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + ZCatalog.manage_options + )) def __init__(self): ZCatalog.__init__(self, self.getId()) @@ -82,6 +88,14 @@ # # Subclass extension interface # + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of action information instances + provided via tool + """ + return self._actions + security.declarePublic( 'enumerateIndexes' ) # Subclass can call def enumerateIndexes( self ): # Return a list of ( index_name, type ) pairs for the initial === CMF/CMFCore/MemberDataTool.py 1.12 => 1.13 === from CMFCorePermissions import ViewManagementScreens import CMFCorePermissions +from ActionProviderBase import ActionProviderBase _marker = [] # Create a new marker object. -class MemberDataTool (UniqueObject, SimpleItem, PropertyManager): +class MemberDataTool (UniqueObject, SimpleItem, PropertyManager, ActionProviderBase): '''This tool wraps user objects, making them act as Member objects. ''' id = 'portal_memberdata' meta_type = 'CMF Member Data Tool' + _actions = [] _v_temps = None _properties = () security = ClassSecurityInfo() - manage_options=( ( { 'label' : 'Overview' + manage_options=( ActionProviderBase.manage_options + + ({ 'label' : 'Overview' , 'action' : 'manage_overview' } , { 'label' : 'Contents' @@ -83,8 +86,11 @@ # 'portal_memberdata' interface methods # security.declarePrivate('listActions') - def listActions(self, info): - return None + def listActions(self, info=None): + """ + Return actions provided via tool. + """ + return self._actions security.declarePrivate('getMemberDataContents') def getMemberDataContents(self): === CMF/CMFCore/MembershipTool.py 1.16 => 1.17 === from CMFCorePermissions import ManagePortal import CMFCorePermissions +from ActionProviderBase import ActionProviderBase import Acquisition default_member_content = '''Default page for %s @@ -37,22 +38,23 @@ in the Tool Box on the left. ''' -class MembershipTool (UniqueObject, SimpleItem): +class MembershipTool (UniqueObject, SimpleItem, ActionProviderBase): # This tool accesses member data through an acl_users object. # It can be replaced with something that accesses member data in # a different way. id = 'portal_membership' meta_type = 'CMF Membership Tool' - + _actions = [] security = ClassSecurityInfo() - manage_options=( { 'label' : 'Overview' - , 'action' : 'manage_overview' - } - , { 'label' : 'Configuration' + manage_options=( ({ 'label' : 'Configuration' , 'action' : 'manage_mapRoles' - } - ) + SimpleItem.manage_options + },) + + ActionProviderBase.manage_options + + ( { 'label' : 'Overview' + , 'action' : 'manage_overview' + }, + ) + SimpleItem.manage_options) # # ZMI methods @@ -387,7 +389,7 @@ security.declarePrivate('listActions') - def listActions(self, info): + def listActions(self): return None security.declarePublic('getHomeFolder') === CMF/CMFCore/PortalFolder.py 1.28 => 1.29 === , 'category' : 'folder' } - , { 'id' : 'syndication' - , 'name' : 'Syndication' - , 'action' : 'synPropertiesForm' - , 'permissions' : (ManageProperties,) - , 'category' : 'folder' - } ) } , === CMF/CMFCore/RegistrationTool.py 1.7 => 1.8 === import CMFCorePermissions import string, random +from ActionProviderBase import ActionProviderBase -class RegistrationTool (UniqueObject, SimpleItem): +class RegistrationTool (UniqueObject, SimpleItem, ActionProviderBase): # This tool creates and modifies users by making calls # to portal_membership. id = 'portal_registration' @@ -37,9 +38,10 @@ security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = (ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + SimpleItem.manage_options + ) + SimpleItem.manage_options) # # ZMI methods @@ -51,9 +53,6 @@ # # 'portal_registration' interface methods # - security.declarePrivate('listActions') - def listActions(self, info): - return none security.declarePublic('isRegistrationAllowed') def isRegistrationAllowed(self, REQUEST): === CMF/CMFCore/SkinsTool.py 1.11 => 1.12 === from AccessControl import ClassSecurityInfo from CMFCorePermissions import ManagePortal, AccessContentsInformation +from ActionProviderBase import ActionProviderBase +from ActionInformation import ActionInformation +from Expression import Expression from OFS.Image import Image from OFS.DTMLMethod import DTMLMethod @@ -53,20 +56,23 @@ 'action':'manage_propertiesForm'}] return tuple(rval) -class SkinsTool(UniqueObject, SkinsContainer, PortalFolder): +class SkinsTool(UniqueObject, SkinsContainer, PortalFolder, ActionProviderBase): ''' This tool is used to supply skins to a portal. ''' id = 'portal_skins' meta_type = 'CMF Skins Tool' + _actions = [] cookie_persistence = 0 security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( modifiedOptions() + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + modifiedOptions() + ) + ActionProviderBase.manage_options + ) def __init__(self): self.selections = PersistentMapping() @@ -89,6 +95,14 @@ request_varname = 'portal_skin' allow_any = 0 selections = None + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of actions information instances + provided by the tool. + """ + return self._actions security.declareProtected(ManagePortal, 'manage_propertiesForm') manage_propertiesForm = DTMLFile('dtml/skinProps', globals()) === CMF/CMFCore/TypesTool.py 1.26 => 1.27 === from Acquisition import aq_base import Products, CMFCorePermissions +from ActionProviderBase import ActionProviderBase +from ActionInformation import ActionInformation +from Expression import Expression from CMFCorePermissions import View, ManagePortal, AccessContentsInformation @@ -501,18 +504,21 @@ , ScriptableTypeInformation.meta_type ) -class TypesTool( UniqueObject, OFS.Folder.Folder ): +class TypesTool( UniqueObject, OFS.Folder.Folder, ActionProviderBase ): """ Provides a configurable registry of portal content types. """ id = 'portal_types' meta_type = 'CMF Types Tool' + _actions = [] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( OFS.Folder.Folder.manage_options + + ActionProviderBase.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + OFS.Folder.Folder.manage_options + )) # # ZMI methods @@ -520,6 +526,14 @@ security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) manage_overview = DTMLFile( 'explainTypesTool', _dtmldir ) + + security.declarePrivate('listActions') + def listActions(self, info=None): + """ + Return a list of action information instances + for actions provided via tool + """ + return self._actions def all_meta_types(self): all = TypesTool.inheritedAttribute('all_meta_types')(self) === CMF/CMFCore/UndoTool.py 1.4 => 1.5 === from string import split from AccessControl import ClassSecurityInfo - +from Expression import Expression +from ActionInformation import ActionInformation +from ActionProviderBase import ActionProviderBase from CMFCorePermissions import ManagePortal, UndoChanges, ListUndoableChanges -class UndoTool (UniqueObject, SimpleItem): +class UndoTool (UniqueObject, SimpleItem, ActionProviderBase): id = 'portal_undo' meta_type = 'CMF Undo Tool' # This tool is used to undo changes. + _actions = [ActionInformation(id='undo' + , title='Undo' + , action=Expression( + text='string: ${portal_url}/undo_form') + , condition=Expression( + text='member') + , permissions=(ListUndoableChanges,) + , category='global' + , visible=1 + )] security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } + manage_options = ( ActionProviderBase.manage_options + + SimpleItem.manage_options + + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , - ) + SimpleItem.manage_options - + )) # # ZMI methods # @@ -46,14 +59,11 @@ manage_overview = DTMLFile( 'explainUndoTool', _dtmldir ) security.declarePrivate('listActions') - def listActions( self, info ): - if info.isAnonymous: - return [] - return [ { 'name': 'Undo' - , 'url': 'undo_form' - , 'permissions': [ ListUndoableChanges ] - , 'category': 'global' - } ] + def listActions(self, info=None): + """ + List actions available through tool + """ + return self._actions # # 'portal_undo' interface methods === CMF/CMFCore/WorkflowTool.py 1.19 => 1.20 === security = ClassSecurityInfo() - manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } - , { 'label' : 'Workflows' + manage_options = ( { 'label' : 'Workflows' , 'action' : 'manage_selectWorkflows' } + , { 'label' : 'Overview', 'action' : 'manage_overview' } ) + Folder.manage_options # From andrew@zope.com Fri Jan 4 19:50:35 2002 From: andrew@zope.com (Andrew Sawyers) Date: Fri, 4 Jan 2002 14:50:35 -0500 Subject: [CMF-checkins] CVS: CMF/CMFCore/dtml - editToolsActions.dtml:1.2 manageActionProviders.dtml:1.2 Message-ID: <200201041950.g04JoZt11174@cvs.baymountain.com> Update of /cvs-repository/CMF/CMFCore/dtml In directory cvs.zope.org:/tmp/cvs-serv10417/CMFCore/dtml Added Files: editToolsActions.dtml manageActionProviders.dtml Log Message: *Merging andrew_ttw_actions-branch into the head *Adds TTW configuration of Action Providers *Allows tools to have actions managed TTW *Added unittests for ActionTool, ActionInformation, and Expression *Added TTW action management to all stock CMF tools *Added Expression module for allowing actions and conditions of actions to be TALES. === CMF/CMFCore/dtml/editToolsActions.dtml 1.1 => 1.2 === + + + + + + + &dtml-form_title; + + + &dtml-form_title; + + + + + + + + + + + + + + + + + + + + Name + + + + + + + + + + + + + + Id + + + + + + + + + + + + + + Action + + + + + + + + + + + + + + Condition + + + + + + + + + + + + + + Permission + + + + + + + (none) + + + + &dtml-sequence-item; + + + + + + + + + + + + Category + + + + + + + + + + + + + + Visible? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Add an action + + + + + + + + Name + + + + + + + + + + + + + + Id + + + + + + + + + + + + + + Action + + + + + + + + + + + + + Condition + + + + + + + + + + + + + + Permission + + + + + + (none) + + &dtml-sequence-item; + + + + + + + + + + + Category + + + + + + + + + + + + + + Visible? + + + + + + + + + + + + + + + + + + + + + + + === CMF/CMFCore/dtml/manageActionProviders.dtml 1.1 => 1.2 === + + +Action Providers + + + + Name + + + + + + &dtml-sequence-item; + + + + + + + + + + + + + + + + + + + + +