def _importOldAction(self, old_action): """Convert a CMF action to an ERP5 action This is used to update an existing site or to import a BT. """ import erp5.portal_type ActionInformation = getattr(erp5.portal_type, 'Action Information') old_action = old_action.__getstate__() action_type = old_action.pop('category', None) action = ActionInformation(self.generateNewId()) for k, v in old_action.iteritems(): if k in ('action', 'condition', 'icon'): if not v: continue v = v.__class__(v.text) setattr( action, { 'id': 'reference', 'priority': 'float_index', 'permissions': 'action_permission', }.get(k, k), v) action.uid = None action = self[self._setObject(action.id, action, set_owner=0)] if action_type: action._setCategoryMembership('action_type', action_type) return action
def fixActionsForType(portal_type, typesTool): if 'actions' in portal_type.installMode: typeInfo = getattr(typesTool, portal_type.portal_type, None) if typeInfo is None: return if hasattr(portal_type, 'actions'): # Look for each action we define in portal_type.actions in # typeInfo.action replacing it if its there and just # adding it if not # rr: this is now trial-and-error programming # I really don't know what's going on here # most importantly I don't know why the default # actions are not set in some cases :-( # (maybe they are removed afterwards sometimes???) # if getattr(portal_type,'include_default_actions', True): if True: default = [ ActionInformation(**action) for action in base_factory_type_information[0]['actions'] ] next = list(typeInfo._actions) all = next + default new = [a.clone() for a in all] else: # If no standard actions are wished don't display them new = [] for action in portal_type.actions: # DM: "Expression" derives from "Persistent" and # we must not put persistent objects into class attributes. # Thus, copy "action" action = action.copy() hits = [a for a in new if a.id == action['id']] # Change action and condition into expressions, if # they are still strings if 'action' in action and \ type(action['action']) in (type(''), type(u'')): action['action'] = Expression(action['action']) if 'condition' in action and \ type(action['condition']) in (type(''), type(u'')): action['condition'] = Expression(action['condition']) if 'name' in action: action['title'] = action['name'] del action['name'] if hits: hits[0].__dict__.update(action) else: new.append(ActionInformation(**action)) typeInfo._actions = tuple(new) typeInfo._p_changed = True if hasattr(portal_type, 'factory_type_information'): typeInfo.__dict__.update(portal_type.factory_type_information) typeInfo._p_changed = True
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.getVisibility(), 1) self.assertEqual(ai.getCategory(), 'object') 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 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 test_construction_with_Expressions(self): ai = ActionInformation(id='view', title='View', action=Expression(text='view'), condition=Expression(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(), 'string:view') self.assertEqual(ai.getVisibility(), 0) self.assertEqual(ai.getCategory(), 'global') self.assertEqual(ai.getPermissions(), ())
def test_create_from_ActionInformation(self): from Products.CMFCore.ActionInformation import ActionInformation WANTED = { 'allowed': True, 'available': True, 'category': 'object', 'description': '', 'id': 'foo', 'title': 'foo', 'url': '', 'visible': True, 'icon': '', 'link_target': None } action = ActionInformation(id='foo') ec = None ai = self._makeOne(action, ec) self.assertEqual(ai['id'], WANTED['id']) self.assertEqual(ai['title'], WANTED['title']) self.assertEqual(ai['description'], WANTED['description']) self.assertEqual(ai['url'], WANTED['url']) self.assertEqual(ai['icon'], WANTED['icon']) self.assertEqual(ai['category'], WANTED['category']) self.assertEqual(ai['visible'], WANTED['visible']) self.assertEqual(ai['available'], WANTED['available']) self.assertEqual(ai['allowed'], WANTED['allowed']) self.assertEqual(ai, WANTED)
def test_listActionInformationActions(self): # Check that listFilteredActionsFor works for objects that return # ActionInformation objects tool = self.tool tool._actions = ( ActionInformation(id='folderContents', title='Folder contents', action=Expression(text='string:' '${folder_url}/folder_contents'), icon_expr=Expression(text='string:' '${folder_url}/icon.gif'), condition=Expression(text='python: ' 'folder is not object'), permissions=('List folder contents',), category='folder', link_target='_top', visible=1),) newSecurityManager(None, OmnipotentUser().__of__(self.app.acl_users)) self.assertEqual(tool.listFilteredActionsFor(self.app.foo), {'workflow': [], 'user': [], 'object': [], 'folder': [{'id': 'folderContents', 'url': 'http://nohost/folder_contents', 'icon': 'http://nohost/icon.gif', 'title': 'Folder contents', 'description': '', 'visible': True, 'available': True, 'allowed': True, 'category': 'folder', 'link_target': '_top'}], 'global': []})
def test_DuplicateActions(self): """ Check that listFilteredActionsFor filters out duplicate actions. """ root = self.root tool = self.tool action = ActionInformation(id='test', title='Test', action=Expression(text='string: a_url'), condition='', permissions=(), category='object', visible=1) tool._actions = [action, action] self.tool.action_providers = ('portal_actions', ) self.assertEqual( tool.listFilteredActionsFor(root)['object'], [{ 'permissions': (), 'id': 'test', 'url': ' a_url', 'name': 'Test', 'visible': 1, 'category': 'object' }])
def doubleCheckDefaultTypeActions(self, ftypes): # rr: for some reason, AT's magic wrt adding the default type actions # stopped working when moving to CMF-2.0 # Instead of trying to resurect the old way (which I tried but couldn't) # I make it brute force here typesTool = getToolByName(self, 'portal_types') defaultTypeActions = [ ActionInformation(**action) for action in base_factory_type_information[0]['actions'] ] for ftype in ftypes: portal_type = ftype.portal_type fti = typesTool.get(portal_type, None) if fti is None: continue actions = list(fti._actions) action_ids = [a.id for a in actions] prepend = [] for a in defaultTypeActions: if a.id not in action_ids: prepend.append(a.clone()) if prepend: fti._actions = tuple(prepend + actions)
def _extractAction(self, properties, index): """ Extract an ActionInformation from the funky form properties. """ id = str(properties.get('id_%d' % index, '')) title = str(properties.get('name_%d' % index, '')) action = str(properties.get('action_%d' % index, '')) icon_expr = str(properties.get('icon_expr_%d' % index, '')) condition = str(properties.get('condition_%d' % index, '')) category = str(properties.get('category_%d' % index, '')) visible = bool(properties.get('visible_%d' % index, False)) permissions = properties.get('permission_%d' % index, ()) link_target = str(properties.get('link_target_%d' % index, '')) if not title: raise ValueError('A title is required.') if category == '': category = 'object' if isinstance(permissions, basestring): permissions = (permissions, ) return ActionInformation(id=id, title=title, action=action, condition=condition, permissions=permissions, category=category, visible=visible, icon_expr=icon_expr, link_target=link_target)
def test_create_from_ActionInformation(self): from Products.CMFCore.ActionInformation import ActionInformation wanted = { 'allowed': True, 'available': True, 'category': 'object', 'id': 'foo', 'name': 'foo', 'permissions': (), 'title': 'foo', 'url': '', 'visible': True } action = ActionInformation(id='foo') ec = None ai = self._makeOne(action, ec) self.assertEqual(ai['id'], wanted['id']) self.assertEqual(ai['title'], wanted['title']) self.assertEqual(ai['url'], wanted['url']) self.assertEqual(ai['permissions'], wanted['permissions']) self.assertEqual(ai['category'], wanted['category']) self.assertEqual(ai['visible'], wanted['visible']) self.assertEqual(ai['available'], wanted['available']) self.assertEqual(ai['allowed'], wanted['allowed']) self.assertEqual(ai, wanted)
def test_listActionInformationActions(self): # Check that listFilteredActionsFor works for objects that return # ActionInformation objects root = self.root tool = self.tool tool._actions = (ActionInformation( id='folderContents', title='Folder contents', action=Expression(text='string:' '${folder_url}/folder_contents'), icon_expr=Expression(text='string:' '${folder_url}/icon.gif'), condition=Expression(text='python: ' 'folder is not object'), permissions=('List folder contents', ), category='folder', visible=1), ) self.assertEqual( tool.listFilteredActionsFor(root.foo), { 'workflow': [], 'user': [], 'object': [], 'folder': [{ 'id': 'folderContents', 'url': 'http://nohost/folder_contents', 'icon': 'http://nohost/icon.gif', 'title': 'Folder contents', 'description': '', 'visible': True, 'available': True, 'allowed': True, 'category': 'folder' }], 'global': [] })
def test_editing(self): ai = ActionInformation(id='view', category='folder', ) ai.edit(id='new_id', title='blah') self.assertEqual(ai.getId(), 'new_id') self.assertEqual(ai.Title(), 'blah') self.assertEqual(ai.Description(), '') self.assertEqual(ai.getCondition(), '') self.assertEqual(ai.getActionExpression(), '') self.assertEqual(ai.getVisibility(), 1) self.assertEqual(ai.getCategory(), 'folder') self.assertEqual(ai.getPermissions(), ())
class DummyProvider(ActionProviderBase, DummyTool): _actions = (ActionInformation(id='an_id', title='A Title', action='', condition='', permissions=(), category='', visible=False), )
def importActionProviders( context ): """ Import action providers and their actions from an XML file. o 'context' must implement IImportContext. o Register via Python: registry = site.portal_setup.getImportStepRegistry() registry.registerStep( 'importActionProviders' , '20040518-01' , Products.CMFSetup.actions.importActionProviders , () , 'Action Provider import' , 'Import action providers registered with ' 'the actions tool, and their actions.' ) o Register via XML: <setup-step id="importActionProviders" version="20040524-01" handler="Products.CMFSetup.actions.importActionProviders" title="Action Provider import" >Import action providers registered with the actions tool, and their actions.</setup-step> """ site = context.getSite() encoding = context.getEncoding() actions_tool = getToolByName( site, 'portal_actions' ) if context.shouldPurge(): for provider_id in actions_tool.listActionProviders(): actions_tool.deleteActionProvider( provider_id ) text = context.readDataFile( _FILENAME ) if text is not None: apc = ActionProvidersConfigurator( site ).__of__( site ) info_list = apc.parseXML( text, encoding ) for p_info in info_list: if p_info[ 'id' ] not in actions_tool.listActionProviders(): actions_tool.addActionProvider( p_info[ 'id' ] ) provider = getToolByName( site, p_info[ 'id' ] ) provider._actions = [ ActionInformation(**a_info) for a_info in p_info['actions'] ] return 'Action providers imported.'
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 = ( ActionProviderBase.manage_options + ({ 'label' : 'Overview', 'action' : 'manage_overview' } , ) + SimpleItem.manage_options ) # # ZMI methods # security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) manage_overview = DTMLFile( 'explainPropertiesTool', _dtmldir ) # # '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): '''Change portal settings''' aq_parent(aq_inner(self)).manage_changeProperties(props) self.MailHost.smtp_host = props['smtp_server'] if hasattr(self, 'propertysheets'): ps = self.propertysheets if hasattr(ps, 'props'): ps.props.manage_changeProperties(props) def title(self): return self.aq_inner.aq_parent.title def smtp_server(self): return self.MailHost.smtp_host
class DummyProvider(ActionProviderBase): _actions = [ ActionInformation(id='an_id', title='A Title', action='', condition='', permissions='', category='', visible=0) ]
def ActionProviderBase_extractAction( self, properties, index ): """ Extract an ActionInformation from the funky form properties. """ id = str( properties.get( 'id_%d' % index, '' ) ) title = str( properties.get( 'title_%d' % index, '' ) ) description = str( properties.get( 'description_%d' % index, '' ) ) action = str( properties.get( 'action_%d' % index, '' ) ) icon = str( properties.get( 'icon_%d' % index, '' ) ) condition = str( properties.get( 'condition_%d' % index, '' ) ) category = str( properties.get( 'category_%d' % index, '' )) visible = properties.get( 'visible_%d' % index, 0 ) permissions = properties.get( 'permission_%d' % index, () ) priority = float( properties.get( 'priority_%d' % index, 1.0 )) if not title: raise ValueError('A title is required.') if action is not '': action = Expression( text=action ) if icon is not '': icon = Expression( text=icon ) if condition is not '': condition = Expression( text=condition ) if category == '': category = 'object' if type( visible ) is not type( 0 ): try: visible = int( visible ) except TypeError: visible = 0 if type( permissions ) is type( '' ): permissions = ( permissions, ) if type( priority ) is not type(1.0): priority = float(priority) return ActionInformation( id=id , title=title , description=description , action=action , icon=icon , condition=condition , permissions=permissions , category=category , visible=visible , priority=priority )
def hitCountUpgrade(self): """Upgrade the installed tool""" out = StringIO() out.write("Upgrading Risa Repository\n") content = getToolByName(self, 'content') fi = FieldIndex('sortTitle') content.catalog._catalog.addIndex('sortTitle', fi) fi._updateProperty('PrenormalizeTerm', 'python: value.lower()') fi._updateProperty('TermType', 'string') fi.sortTitle._updateProperty('Name', 'title') fi.sortTitle._updateProperty('Normalizer', 'python: here.stripArticles(value)') extra = Empty() extra.indexed_attrs = 'keywords' content.catalog.addIndex('keywordscase', 'KeywordIndex', extra) content.catalog.delColumn('icon') content.catalog.addColumn('getIcon') content.catalog.addColumn('url') content.catalog.addColumn('authors') content.catalog.addColumn('instructor') out.write("Upgraded catalog\n") types_tool = getToolByName(self, 'portal_types') # Plone1 version #types_tool.Repository._actions = ({'id':'view', 'name':'Browse', 'action':'browse_content', 'permissions':('View',),'visible':0},) types_tool.Repository._actions = [ ActionInformation('view', title='Browse', action='browse_content', permissions=(CMFCorePermissions.View), visible=0) ] out.write("Upgraded actions\n") right_slots = [ 'here/portlet_newest_content/macros/portlet', 'here/portlet_hits/macros/portlet' ] content._setProperty('right_slots', right_slots, type='lines') out.write("Upgraded portlets\n") content.catalog.refreshCatalog() out.write("Refreshed catalog\n") return out.getvalue()
def setUp(self): SecurityTest.setUp(self) app = self.app app._setObject('portal', DummyContent('portal', url='url_portal')) self.portal = app.portal self.folder = DummyContent('foo', url='url_foo') self.object = DummyContent('bar', url='url_bar') self.ai = ActionInformation(id='view', title='View', action=Expression(text='view'), condition=Expression(text='member'), category='global', visible=1)
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.getVisibility(), 1) self.assertEqual(ai.getCategory(), 'object') self.assertEqual(ai.getPermissions(), ())
def _importOldAction(self, old_action): """Convert a CMF action to an ERP5 action This is used to update an existing site or to import a BT. """ import erp5.portal_type ActionInformation = getattr(erp5.portal_type, "Action Information") old_action = old_action.__getstate__() action_type = old_action.pop("category", None) action = ActionInformation(self.generateNewId()) for k, v in old_action.iteritems(): if k in ("action", "condition", "icon"): if not v: continue v = v.__class__(v.text) setattr( action, {"id": "reference", "priority": "float_index", "permissions": "action_permission"}.get(k, k), v ) action.uid = None action = self[self._setObject(action.id, action, set_owner=0)] if action_type: action._setCategoryMembership("action_type", action_type) return action
def _importOldAction(self, old_action): """Convert a CMF action to an ERP5 action This is used to update an existing site or to import a BT. """ import erp5.portal_type ActionInformation = getattr(erp5.portal_type, 'Action Information') old_action = old_action.__getstate__() action_type = old_action.pop('category', None) action = ActionInformation(self.generateNewId()) for k, v in old_action.iteritems(): if k in ('action', 'condition', 'icon'): if not v: continue v = v.__class__(v.text) setattr(action, {'id': 'reference', 'priority': 'float_index', 'permissions': 'action_permission', }.get(k, k), v) action.uid = None action = self[self._setObject(action.id, action, set_owner=0)] if action_type: action._setCategoryMembership('action_type', action_type) return action
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 listActions(self, info=None, object=None): """ List all the actions defined by a provider. """ if object is None: if info is None: # There is no support for global actions return () else: object = info.content actions = [] for menu_id in _listMenuIds(): for entry in getMenu(menu_id, object, self.REQUEST): # The action needs a unique name, so I'll build one # from the object_id and the action url. That is sure # to be unique. action = str(entry['action']) if object is None: act_id = 'action_%s' % action else: act_id = 'action_%s_%s' % (object.getId(), action) if entry.get('filter') is None: filter = None else: filter = Expression(text=str(entry['filter'])) title = entry['title'] # Having bits of unicode here can make rendering very confused, # so we convert it to plain strings, but NOT if it is a # messageID. In Zope 3.2 there are two types of messages, # Message and MessageID, where MessageID is depracated. We can # type-check for both but that provokes a deprecation warning, # so we check for the "domain" attribute instead. if not hasattr(title, 'domain'): title = str(title) act = ActionInformation(id=act_id, title=title, action=Expression(text='string:%s' % action), condition=filter, category=str(menu_id), visible=1) actions.append(act) return tuple(actions)
def ActionProviderBase_addAction( self , id , name , action , condition , permission , category , icon=None , visible=1 , priority=1.0 , REQUEST=None , description='' ): """ Add an action to our list. """ if not name: raise ValueError('A name is required.') a_expr = action and Expression(text=str(action)) or '' i_expr = icon and Expression(text=str(icon)) or '' c_expr = condition and Expression(text=str(condition)) or '' if type( permission ) != type( () ): permission = permission and (str(permission),) or () new_actions = self._cloneActions() new_action = ActionInformation( id=str(id) , title=str(name) , description=str(description) , action=a_expr , icon=i_expr , condition=c_expr , permissions=permission , category=str(category) , visible=int(visible) , priority=float(priority) ) new_actions.append( new_action ) self._actions = tuple( new_actions ) if REQUEST is not None: return self.manage_editActionsForm( REQUEST, manage_tabs_message='Added.')
def test_construction_with_Expressions(self): ai = ActionInformation(id='view' , title='View' , action=Expression( text='view') , condition=Expression( 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(), 'string:view') self.assertEqual(ai.getVisibility(), 0) self.assertEqual(ai.getCategory(), 'global') self.assertEqual(ai.getPermissions(), ())
def _exportOldAction(self, action): """Convert an ERP5 action to a CMF action This is used to export a BT. """ from Products.CMFCore.ActionInformation import ActionInformation old_action = ActionInformation(action.reference, category=action.getActionType(), priority=action.getFloatIndex(), permissions=tuple(action.getActionPermissionList())) for k, v in action.__dict__.iteritems(): if k in ('action', 'condition', 'icon'): if not v: continue v = v.__class__(v.text) elif k in ('id', 'float_index', 'action_permission', 'reference'): continue setattr(old_action, k, v) return old_action
def addAction(self, id, name, action, condition, permission, category, visible=1, icon_expr='', link_target='', description='', REQUEST=None): """ Add an action to our list. """ if not name: raise ValueError('A name is required.') action = action and str(action) or '' condition = condition and str(condition) or '' if not isinstance(permission, tuple): permission = (str(permission), ) new_actions = self._cloneActions() new_action = ActionInformation(id=str(id), title=str(name), description=str(description), category=str(category), condition=condition, permissions=permission, visible=bool(visible), action=action, icon_expr=icon_expr, link_target=link_target) new_actions.append(new_action) self._actions = tuple(new_actions) if REQUEST is not None: return self.manage_editActionsForm(REQUEST, manage_tabs_message='Added.')
def actions_add_type_action(self, portal_type, after, action_id, **kwargs): """Add a ``portal_type`` action from the type identified by ``portal_type``, the position could be definded by the ``after`` attribute. If the after action could not be found, the action will be inserted at the end of the list.""" actions = [] found = False ttool = self.getToolByName('portal_types') fti = ttool.get(portal_type) new_action = ActionInformation(id=action_id, **kwargs) for action in fti._actions: # pylint: disable=W0212 actions.append(action) if action.id == after: actions.append(new_action) found = True if not found: actions.append(new_action) fti._actions = tuple(actions) # pylint: disable=W0212
def _makeOne(self, *args, **kw): from Products.CMFCore.ActionInformation import ActionInformation return ActionInformation(*args, **kw)
def getAction(self, ec): res = ActionInformation.getAction(self, ec) res['description'] = self.getDescription() return res
def __init__(self, appId, **kwargs): self.appId = appId ActionInformation.__init__(self, **kwargs)
class DiscussionTool(UniqueObject, SimpleItem, ActionProviderBase): """ Links content to discussions. """ __implements__ = (IDiscussionTool, ActionProviderBase.__implements__) 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=(ReplyToItem, ), category='object', visible=1), ) security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + SimpleItem.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainDiscussionTool', _dtmldir) # # 'portal_discussion' interface methods # security.declarePublic('overrideDiscussionFor') def overrideDiscussionFor(self, content, allowDiscussion): """ Override discussability for the given object or clear the setting. """ mtool = getToolByName(self, 'portal_membership') if not mtool.checkPermission(ModifyPortalContent, content): raise AccessControl_Unauthorized if allowDiscussion is None or allowDiscussion == 'None': if hasattr(aq_base(content), 'allow_discussion'): del content.allow_discussion else: content.allow_discussion = bool(allowDiscussion) security.declarePublic('getDiscussionFor') def getDiscussionFor(self, content): """ Get DiscussionItemContainer for content, create it if necessary. """ if not self.isDiscussionAllowedFor(content): raise DiscussionNotAllowed if not IDiscussionResponse.isImplementedBy(content) and \ getattr( aq_base(content), 'talkback', None ) is None: # Discussion Items use the DiscussionItemContainer object of the # related content item, so only create one for other content items self._createDiscussionFor(content) return content.talkback # Return wrapped talkback security.declarePublic('isDiscussionAllowedFor') def isDiscussionAllowedFor(self, content): """ Get boolean indicating whether discussion is allowed for content. """ if hasattr(aq_base(content), 'allow_discussion'): return bool(content.allow_discussion) typeInfo = getToolByName(self, 'portal_types').getTypeInfo(content) if typeInfo: return bool(typeInfo.allowDiscussion()) return False # # Utility methods # security.declarePrivate('_createDiscussionFor') def _createDiscussionFor(self, content): """ Create DiscussionItemContainer for content, if allowed. """ if not self.isDiscussionAllowedFor(content): raise DiscussionNotAllowed content.talkback = DiscussionItemContainer() return content.talkback
class RegistrationTool(BaseTool): """ Manage through-the-web signup policies. """ __implements__ = BaseTool.__implements__ 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=(AddPortalMember,) , category='user' , condition=Expression(text='not: member') , visible=1 ) , ) security = ClassSecurityInfo() # # ZMI methods # security.declareProtected( ManagePortal, 'manage_overview' ) manage_options = ( ActionProviderBase.manage_options + ( { 'label' : 'Overview' , 'action' : 'manage_overview' } , ) ) manage_overview = DTMLFile( 'explainRegistrationTool', _dtmldir ) # # 'portal_registration' interface # security.declarePublic( 'testPasswordValidity' ) def testPasswordValidity(self, password, confirm=None): """ Verify that the password satisfies the portal's requirements. o If the password is valid, return None. o If not, return a string explaining why. """ if len(password) < 5 and not _checkPermission('Manage portal', self): return 'Your password must contain at least 5 characters.' if confirm is not None and confirm != password: return ( 'Your password and confirmation did not match. ' + 'Please try again.' ) return None security.declarePublic( 'testPropertiesValidity' ) def testPropertiesValidity(self, props, member=None): """ Verify that the properties supplied satisfy portal's requirements. o If the properties are valid, return None. o If not, return a string explaining why. """ if member is None: # New member. username = props.get('username', '') if not username: return 'You must enter a valid name.' if not self.isMemberIdAllowed(username): return ('The login name you selected is already ' 'in use or is not valid. Please choose another.') if not props.get('email'): return 'You must enter a valid email address.' else: # Existing member. # Not allowed to clear an existing non-empty email. if (member.getProperty('email') and not props.get('email', 'NoPropIsOk')): return 'You must enter a valid email address.' return None security.declarePublic( 'mailPassword' ) def mailPassword(self, forgotten_userid, REQUEST): """ Email a forgotten password to a member. o Raise an exception if user ID is not found. """ membership = getToolByName(self, 'portal_membership') member = membership.getMemberById(forgotten_userid) if member is None: raise 'NotFound', 'The username you entered could not be found.' # assert that we can actually get an email address, otherwise # the template will be made with a blank To:, this is bad if not member.getProperty('email'): raise 'ValueError', 'That user does not have an email address.' # Rather than have the template try to use the mailhost, we will # render the message ourselves and send it from here (where we # don't need to worry about 'UseMailHost' permissions). mail_text = self.mail_password_template( self , REQUEST , member=member , password=member.getPassword() ) host = self.MailHost host.send( mail_text ) return self.mail_password_response( self, REQUEST ) security.declarePublic( 'registeredNotify' ) def registeredNotify( self, new_member_id ): """ Handle mailing the registration / welcome message. """ membership = getToolByName( self, 'portal_membership' ) member = membership.getMemberById( new_member_id ) if member is None: raise 'NotFound', 'The username you entered could not be found.' password = member.getPassword() email = member.getProperty( 'email' ) if email is None: raise ValueError( 'Member %s has no e-mail address!' % new_member_id ) # Rather than have the template try to use the mailhost, we will # render the message ourselves and send it from here (where we # don't need to worry about 'UseMailHost' permissions). mail_text = self.registered_notify_template( self , self.REQUEST , member=member , password=password , email=email ) host = self.MailHost host.send( mail_text ) return self.mail_password_response( self, self.REQUEST ) security.declareProtected(ManagePortal, 'editMember') def editMember( self , member_id , properties=None , password=None , roles=None , domains=None ): """ Edit a user's properties and security settings o Checks should be done before this method is called using testPropertiesValidity and testPasswordValidity """ mtool = getToolByName(self, 'portal_membership') member = mtool.getMemberById(member_id) member.setMemberProperties(properties) member.setSecurityProfile(password,roles,domains) return member