From 7447262a9acd21e6fced205f3b3d999f22bada87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com> Date: Fri, 7 May 2010 12:32:13 +0000 Subject: [PATCH] Extends Types Tool to support multiple types providers. A type provider is a container for type informations, by default we only have portal_types, but other types providers can be registered. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@35109 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5Type/Tool/TypesTool.py | 51 +++++++++++++++++++-- product/ERP5Type/interfaces/__init__.py | 1 + product/ERP5Type/interfaces/types_tool.py | 55 +++++++++++++++++++++++ product/ERP5Type/tests/testERP5Type.py | 43 ++++++++++++++++-- 4 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 product/ERP5Type/interfaces/types_tool.py diff --git a/product/ERP5Type/Tool/TypesTool.py b/product/ERP5Type/Tool/TypesTool.py index ac07accc15..d513d42126 100644 --- a/product/ERP5Type/Tool/TypesTool.py +++ b/product/ERP5Type/Tool/TypesTool.py @@ -21,14 +21,26 @@ from Acquisition import aq_base from AccessControl import ClassSecurityInfo from OFS.Folder import Folder as OFSFolder import transaction -from Products.CMFCore import TypesTool as CMFCore_TypesTool +from Products.CMFCore import TypesTool as CMFCore_TypesToolModule from Products.ERP5Type.Tool.BaseTool import BaseTool from Products.ERP5Type import Permissions from Products.ERP5Type.ERP5Type import ERP5TypeInformation from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod from zLOG import LOG, WARNING, PANIC +from Products.ERP5Type.interfaces import ITypeProvider, ITypesTool -class TypesTool(BaseTool, CMFCore_TypesTool.TypesTool): + +CMFCore_TypesTool = CMFCore_TypesToolModule.TypesTool + +class TypeProvider(BaseTool, CMFCore_TypesTool): + """Provides portal content types + """ + zope.interface.implements(ITypeProvider) + + +_MARKER = [] + +class TypesTool(TypeProvider): """Provides a configurable registry of portal content types """ id = 'portal_types' @@ -36,9 +48,40 @@ class TypesTool(BaseTool, CMFCore_TypesTool.TypesTool): portal_type = 'Types Tool' allowed_types = () + zope.interface.implements(ITypesTool) + + # TODO: UI to configure this is missing + type_provider_list = ( 'portal_types', ) + security = ClassSecurityInfo() security.declareObjectProtected(Permissions.AccessContentsInformation) + def listTypeInfo(self, container=None): + """List type information from all providers + """ + listTypeInfo = CMFCore_TypesTool.listTypeInfo + type_info_list = [] + for provider in self.type_provider_list: + provider_value = getattr(self, provider, None) + if provider_value is not None: + type_info_list.extend( + listTypeInfo(provider_value, container=container)) + return type_info_list + + def _getOb(self, id, default=_MARKER): + """Get a type information from a provider + """ + _getOb = CMFCore_TypesTool._getOb + for provider in self.type_provider_list: + provider_value = getattr(self, provider, None) + if provider_value is not None: + ob = _getOb(provider_value, id, default=default) + if ob is not default: + return ob + if ob is _MARKER: + raise AttributeError, id + return ob + security.declarePrivate('getActionListFor') def getActionListFor(self, ob=None): """Return all actions applicable to the object""" @@ -238,4 +281,6 @@ class OldTypesTool(OFSFolder): return OFSFolder.__of__(self, parent) return UnrestrictedMethod(base_self._migrateTypesTool)(parent) -CMFCore_TypesTool.TypesTool = OldTypesTool +# Change the CMFCore's TypesTool to automatically migrate to ERP5Type's +# TypesTool +CMFCore_TypesToolModule.TypesTool = OldTypesTool diff --git a/product/ERP5Type/interfaces/__init__.py b/product/ERP5Type/interfaces/__init__.py index b422b9c0b8..54bba28f86 100644 --- a/product/ERP5Type/interfaces/__init__.py +++ b/product/ERP5Type/interfaces/__init__.py @@ -10,3 +10,4 @@ from category_access_provider import ICategoryAccessProvider from value_access_provider import IValueAccessProvider from constraint import IConstraint from role_provider import ILocalRoleAssignor, ILocalRoleGenerator +from types_tool import ITypesTool, ITypeProvider diff --git a/product/ERP5Type/interfaces/types_tool.py b/product/ERP5Type/interfaces/types_tool.py new file mode 100644 index 0000000000..6e351d8fae --- /dev/null +++ b/product/ERP5Type/interfaces/types_tool.py @@ -0,0 +1,55 @@ +############################################################################## +# +# Copyright (c) 2010 Nexedi SARL and Contributors. All Rights Reserved. +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly advised to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +"""Types Tool Interfaces. +""" + +from zope.interface import Interface +from zope.interface import Attribute +try: + from Products.CMFCore.interfaces import ITypesTool as ICMFCoreTypesTool +except ImportError: + # on CMF 1.5, this interface is generated by Five, and is not available at + # this point + class ICMFCoreTypesTool(Interface): + pass + + +class ITypesTool(ICMFCoreTypesTool): + """ERP5Type's types tool. + + ERP5Type's types tool extends CMF types tool, by looking up requested types + into registered types providers. + """ + type_provider_list = Attribute('type_provider_list', + 'List of ids of types providers') + +class ITypeProvider(ICMFCoreTypesTool): + """A type provider contains type information, and conforms to CMF's + TypesTool interface, especially listTypeInfo and getTypeInfo methods. + """ + diff --git a/product/ERP5Type/tests/testERP5Type.py b/product/ERP5Type/tests/testERP5Type.py index adab7c8dac..5e44c49ad0 100644 --- a/product/ERP5Type/tests/testERP5Type.py +++ b/product/ERP5Type/tests/testERP5Type.py @@ -147,13 +147,13 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor): return str(randint(-10000000,100000000)) def getTemplateTool(self): - return getattr(self.getPortal(), 'portal_templates', None) + return getattr(self.portal, 'portal_templates', None) def getCategoryTool(self): - return getattr(self.getPortal(), 'portal_categories', None) + return getattr(self.portal, 'portal_categories', None) def getTypeTool(self): - return getattr(self.getPortal(), 'portal_types', None) + return getattr(self.portal, 'portal_types', None) # Here are the tests def testHasTemplateTool(self): @@ -2735,6 +2735,43 @@ class TestPropertySheet: self.assertNotEquals(None, method) self.assertTrue(method()) + def test_type_provider(self): + from Products.ERP5Type.Tool.TypesTool import TypeProvider + class DummyTypeProvider(TypeProvider): + id = 'dummy_type_provider' + # portal_type = 'Dummy Type Provider' + + self.portal._setObject('dummy_type_provider', DummyTypeProvider()) + types_tool = self.portal.portal_types + # register our dummy type provider + types_tool.type_provider_list = types_tool.type_provider_list + ( + 'dummy_type_provider',) + + # types created in our type provider are available + dummy_type = self.portal.dummy_type_provider.newContent( + portal_type='Base Type', + id='Dummy Type', + type_factory_method_id='addFolder', ) + + # our type is available from types tool + self.assertNotEquals(None, types_tool.getTypeInfo('Dummy Type')) + self.assertTrue('Dummy Type' in [ti.getId() for ti in + types_tool.listTypeInfo()]) + + # not existing types are not an error + self.assertEquals(None, types_tool.getTypeInfo(self.id())) + + # we can create instances from our type provider + container = self.portal.newContent(portal_type='Folder', id='test_folder') + dummy_instance = container.newContent(portal_type='Dummy Type') + + # and use generated accessors on them + dummy_type.edit(type_property_sheet_list=('Reference', )) + + dummy_instance.setReference('test') + self.assertEquals('test', dummy_instance.getReference()) + + class TestAccessControl(ERP5TypeTestCase): # Isolate test in a dedicaced class in order not to break other tests # when this one fails. -- 2.30.9