diff --git a/.meta.toml b/.meta.toml index 46eeeeff..e6f53a10 100644 --- a/.meta.toml +++ b/.meta.toml @@ -7,7 +7,7 @@ commit-id = "55bda5c9" [pyproject] codespell_ignores = "hove" -dependencies_ignores = "['plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield']" +dependencies_ignores = "['plone.app.content', 'plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield']" [flake8] extra_lines = """ diff --git a/news/3858.internal b/news/3858.internal new file mode 100644 index 00000000..3fde256c --- /dev/null +++ b/news/3858.internal @@ -0,0 +1,3 @@ +Make the dependency on ``plone.app.content`` conditional. +This is for ``INameFromTitle``, which we want to move to ``plone.base``. +[maurits] diff --git a/plone/app/dexterity/behaviors/configure.zcml b/plone/app/dexterity/behaviors/configure.zcml index c28738fe..aee0d089 100644 --- a/plone/app/dexterity/behaviors/configure.zcml +++ b/plone/app/dexterity/behaviors/configure.zcml @@ -59,23 +59,31 @@ for="plone.dexterity.interfaces.IDexterityContent" /> - - + + + + - - + + - + + >> portal = layer['portal'] - >>> from plone.dexterity.fti import DexterityFTI - >>> fti = DexterityFTI('dinosaur') - >>> portal.portal_types._setObject('dinosaur', fti) - 'dinosaur' - >>> fti.klass = 'plone.dexterity.content.Container' - >>> fti.filter_content_types = False - -We can declare that it supports the "name from title" behavior defined in -plone.app.content (normally this would be done via Generic Setup):: - - >>> fti.behaviors = ('plone.app.content.interfaces.INameFromTitle', - ... 'plone.app.dexterity.behaviors.metadata.IBasic') - -Now let's fire up the browser and confirm that new content gets renamed -appropriately:: - - >>> from plone.app.testing import TEST_USER_ID, TEST_USER_NAME, TEST_USER_PASSWORD, setRoles - >>> setRoles(portal, TEST_USER_ID, ['Manager']) - >>> import transaction; transaction.commit() - >>> from plone.testing.z2 import Browser - >>> browser = Browser(layer['app']) - >>> browser.addHeader('Authorization', 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,)) - - >>> browser.open('http://nohost/plone/++add++dinosaur') - >>> browser.getControl('Title').value = 'Brachiosaurus' - >>> browser.getControl('Save').click() - >>> browser.url - 'http://nohost/plone/brachiosaurus/view' - - -Title-to-id within a Dexterity container ----------------------------------------- - -Does it still work if we're adding content within a Dexterity container? Let's -check:: - - >>> browser.open('http://nohost/plone/brachiosaurus/++add++dinosaur') - >>> browser.getControl('Title').value = 'Baby Brachiosaurus' - >>> browser.getControl('Save').click() - >>> browser.url - 'http://nohost/plone/brachiosaurus/baby-brachiosaurus/view' diff --git a/plone/app/dexterity/tests/test_doctests.py b/plone/app/dexterity/tests/test_doctests.py index ecdfce99..6b361554 100644 --- a/plone/app/dexterity/tests/test_doctests.py +++ b/plone/app/dexterity/tests/test_doctests.py @@ -8,7 +8,6 @@ tests = ( "discussion.txt", "editing.rst", - "namefromtitle.txt", "metadata.txt", "nextprevious.txt", "filename.txt", diff --git a/plone/app/dexterity/tests/test_namefromtitle.py b/plone/app/dexterity/tests/test_namefromtitle.py new file mode 100644 index 00000000..94d137b7 --- /dev/null +++ b/plone/app/dexterity/tests/test_namefromtitle.py @@ -0,0 +1,84 @@ +from plone.app.dexterity.testing import DEXTERITY_FUNCTIONAL_TESTING +from plone.app.testing import setRoles +from plone.app.testing import TEST_USER_ID +from plone.app.testing import TEST_USER_NAME +from plone.app.testing import TEST_USER_PASSWORD +from plone.dexterity.fti import DexterityFTI +from plone.testing.zope import Browser + +import transaction +import unittest + + +def add_dinosaur_type(portal, behavior_name): + fti = DexterityFTI("dinosaur") + portal.portal_types._setObject("dinosaur", fti) + fti.klass = "plone.dexterity.content.Container" + fti.filter_content_types = False + fti.behaviors = ( + behavior_name, + "plone.basic", + ) + return fti + + +class NameFromTitleFunctionalTest(unittest.TestCase): + """Test name-from-title using named behavior.""" + + layer = DEXTERITY_FUNCTIONAL_TESTING + behavior_name = "plone.namefromtitle" + + def setUp(self): + app = self.layer["app"] + self.portal = self.layer["portal"] + self.request = self.layer["request"] + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + self.portal_url = self.portal.absolute_url() + + # Say we have a 'Dinosaur' content type: + self.fti = add_dinosaur_type(self.portal, self.behavior_name) + + transaction.commit() + self.browser = Browser(app) + self.browser.handleErrors = False + self.browser.addHeader( + "Authorization", + "Basic {}:{}".format( + TEST_USER_NAME, + TEST_USER_PASSWORD, + ), + ) + + def test_create(self): + self.browser.open(f"{self.portal_url}/++add++dinosaur") + self.browser.getControl("Title").value = "Brachiosaurus" + self.browser.getControl("Save").click() + self.assertEqual(self.browser.url, f"{self.portal_url}/brachiosaurus/view") + + # Does it still work if we are adding content within a container? + self.browser.open(f"{self.portal_url}/brachiosaurus/++add++dinosaur") + self.browser.getControl("Title").value = "Baby Brachiosaurus" + self.browser.getControl("Save").click() + self.assertEqual( + self.browser.url, + f"{self.portal_url}/brachiosaurus/baby-brachiosaurus/view", + ) + + +class PloneAppContentNameFromTitleFunctionalTest(NameFromTitleFunctionalTest): + """Test name-from-title using old plone.app.content behavior interface.""" + + behavior_name = "plone.app.content.interfaces.INameFromTitle" + + +# We could test that you can use the new interface location as behavior name, +# but this fails, and this is fine: it was never supported. +# In all cases the named behavior is recommended. +# +# class PloneBaseNameFromTitleFunctionalTest(NameFromTitleFunctionalTest): +# """Test name-from-title using new plone.base behavior interface.""" +# behavior_name = "plone.base.interfaces.INameFromTitle" + + +def test_suite(): + return unittest.defaultTestLoader.loadTestsFromName(__name__) diff --git a/pyproject.toml b/pyproject.toml index 6e0a8720..3aac14c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,7 +92,7 @@ Zope = [ 'Products.CMFCore', 'Products.CMFDynamicViewFTI', ] python-dateutil = ['dateutil'] -ignore-packages = ['plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield'] +ignore-packages = ['plone.app.content', 'plone.app.relationfield', 'plone.directives.form', 'plone.directives.dexterity', 'five.grok', 'plone.app.intid', 'plone.contentrules', 'plone.schema', 'z3c.relationfield'] ## # Add extra configuration options in .meta.toml: diff --git a/setup.py b/setup.py index 43b15267..84f69e45 100644 --- a/setup.py +++ b/setup.py @@ -62,7 +62,6 @@ # Plone/Zope core "lxml", "plone.base", - "plone.app.content", "plone.app.uuid", "plone.app.z3cform>=1.1.0", "plone.autoform>=1.1",