diff --git a/docs/HISTORY.txt b/docs/HISTORY.txt index c51b411..ed60f58 100644 --- a/docs/HISTORY.txt +++ b/docs/HISTORY.txt @@ -1,8 +1,14 @@ Changelog ========= -2.0.1 (unreleased) ------------------- +2.1 (unreleased) +---------------- + +* Overrride allowedContentTypes and invokeFactory from PortalFolder + to mimic the behavior of Archetypes based folders. This allows the + registration of IConstrainTypes adapters to actually have the + expected effect. + [gaudenzius] - The default attribute accessor now also looks through subtypes (behaviors) to find a field default. @@ -34,7 +40,6 @@ Changelog * Update package dependencies and imports as appropriate for Zope 2.12 & 2.13. [davisagli] - 1.1.2 - 2012-02-20 ------------------ diff --git a/plone/dexterity/content.py b/plone/dexterity/content.py index 2c6912b..bdb1bda 100644 --- a/plone/dexterity/content.py +++ b/plone/dexterity/content.py @@ -31,6 +31,7 @@ import Products.CMFCore.permissions from Products.CMFCore.PortalContent import PortalContent from Products.CMFCore.PortalFolder import PortalFolderBase from Products.CMFCore.CMFCatalogAware import CMFCatalogAware +from Products.CMFPlone.interfaces import IConstrainTypes from Products.CMFDefault.DublinCore import DefaultDublinCoreImpl from Products.CMFDefault.utils import tuplize @@ -347,6 +348,30 @@ class Container(DAVCollectionMixin, BrowserDefaultMixin, CMFCatalogAware, CMFOrd "Do not have permissions to remove this object") return super(Container, self).manage_delObjects(ids, REQUEST=REQUEST) + # override PortalFolder's allowedContentTypes to respect IConstrainTypes + # adapters + def allowedContentTypes(self, context=None): + if not context: + context = self + + constrains = IConstrainTypes(context, None) + if not constrains: + return super(Container, self).allowedContentTypes() + + return constrains.allowedContentTypes() + + # override PortalFolder's invokeFactory to respect IConstrainTypes + # adapters + def invokeFactory(self, type_name, id, RESPONSE=None, *args, **kw): + """Invokes the portal_types tool + """ + constrains = IConstrainTypes(self, None) + + if constrains and not type_name in [fti.getId() for fti in constrains.allowedContentTypes()]: + raise ValueError('Subobject type disallowed by IConstrainTypes adapter: %s' % type_name) + + return super(Container, self).invokeFactory(type_name, id, RESPONSE, *args, **kw) + def reindexOnModify(content, event): """When an object is modified, re-index it in the catalog diff --git a/plone/dexterity/tests/test_content.py b/plone/dexterity/tests/test_content.py index ff9fdd7..c0725c0 100644 --- a/plone/dexterity/tests/test_content.py +++ b/plone/dexterity/tests/test_content.py @@ -3,11 +3,13 @@ import unittest from plone.mocktestcase import MockTestCase from zope.interface import Interface, alsoProvides -from zope.component import provideAdapter +from zope.component import provideAdapter, getUtility import zope.schema -from plone.dexterity.interfaces import IDexterityFTI +from Products.CMFPlone.interfaces import IConstrainTypes + +from plone.dexterity.interfaces import IDexterityFTI, IDexterityContainer from plone.dexterity.fti import DexterityFTI from plone.dexterity.schema import SCHEMA_CACHE @@ -678,6 +680,31 @@ class TestContent(MockTestCase): container.manage_delObjects(['test']) self.assertFalse('test' in container) + def test_iconstraintypes_adapter(self): + + class DummyConstrainTypes(object): + + def __init__(self, context): + self.context = context + + def allowedContentTypes(self): + fti = getUtility(IDexterityFTI, name=u"testtype") + return [fti] + + self.mock_adapter(DummyConstrainTypes, IConstrainTypes, (IDexterityContainer, )) + + # FTI mock + fti_mock = self.mocker.proxy(DexterityFTI(u"testtype")) + self.expect(fti_mock.getId()).result(u"testtype") + self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype") + + self.replay() + + folder = Container(id="testfolder") + + self.assertEquals(folder.allowedContentTypes(), [fti_mock]) + self.assertRaises(ValueError, folder.invokeFactory, u"disallowed_type", id="test") + def test_suite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) diff --git a/setup.py b/setup.py index c71e9e7..fd447ee 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages import os -version = '2.0.1.dev0' +version = '2.1.dev0' setup(name='plone.dexterity', version=version,