From 2233d0b53500b7aaa5395cda3e1076db19d7409f Mon Sep 17 00:00:00 2001 From: Gaudenz Steinlin Date: Mon, 17 Oct 2011 15:55:33 +0200 Subject: [PATCH] Use IConstrainTypes adapters for dexterity content 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. --- docs/HISTORY.txt | 11 +++++++--- plone/dexterity/content.py | 25 +++++++++++++++++++++ plone/dexterity/tests/test_content.py | 31 +++++++++++++++++++++++++-- setup.py | 2 +- 4 files changed, 63 insertions(+), 6 deletions(-) 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,