diff --git a/news/1796.bugfix b/news/1796.bugfix new file mode 100644 index 0000000000..f5635497e5 --- /dev/null +++ b/news/1796.bugfix @@ -0,0 +1 @@ +Get schemata for behaviors defined in the context. @mamico diff --git a/src/plone/restapi/testing.zcml b/src/plone/restapi/testing.zcml index d1cd9a2dbb..4ec899bcf0 100644 --- a/src/plone/restapi/testing.zcml +++ b/src/plone/restapi/testing.zcml @@ -33,4 +33,6 @@ provides=".tests.dxtypes.ITestAnnotationsBehavior" /> + + diff --git a/src/plone/restapi/tests/dxtypes.py b/src/plone/restapi/tests/dxtypes.py index b3632d41d9..d1e76b04d1 100644 --- a/src/plone/restapi/tests/dxtypes.py +++ b/src/plone/restapi/tests/dxtypes.py @@ -6,7 +6,10 @@ from plone.autoform.directives import read_permission from plone.autoform.directives import write_permission from plone.autoform.interfaces import IFormFieldProvider +from plone.behavior.interfaces import IBehavior +from plone.dexterity.behavior import DexterityBehaviorAssignable from plone.dexterity.content import Item +from plone.dexterity.interfaces import IDexterityContent from plone.namedfile import field as namedfile from plone.restapi.tests.helpers import ascii_token from plone.supermodel import model @@ -17,6 +20,8 @@ from z3c.relationfield.schema import RelationChoice from z3c.relationfield.schema import RelationList from zope import schema +from zope.component import adapter +from zope.component import queryUtility from zope.interface import directlyProvides from zope.interface import implementer from zope.interface import Invalid @@ -317,3 +322,21 @@ class ITestBehavior(model.Schema): @provider(IFormFieldProvider) class ITestAnnotationsBehavior(model.Schema): test_annotations_behavior_field = schema.TextLine(required=False) + + +class IInstanceBehaviorAssignableContent(IDexterityContent): + """Marks dexterity content to be extensible by instance behaviors.""" + + +@adapter(IInstanceBehaviorAssignableContent) +class DexterityInstanceBehaviorAssignable(DexterityBehaviorAssignable): + """Per instance specification of plone.behavior behaviors. + - add tests.restapi.test_behavior + - remove plone.dublincore + """ + + def enumerateBehaviors(self): + for behavior in super().enumerateBehaviors(): + if behavior.name not in ["plone.dublincore"]: + yield behavior + yield queryUtility(IBehavior, name="tests.restapi.test_behavior") diff --git a/src/plone/restapi/tests/test_types.py b/src/plone/restapi/tests/test_types.py index a19186ca01..7014e247c5 100644 --- a/src/plone/restapi/tests/test_types.py +++ b/src/plone/restapi/tests/test_types.py @@ -4,7 +4,9 @@ from plone.app.textfield import RichText from plone.autoform import directives as form from plone.dexterity.fti import DexterityFTI +from plone.dexterity.utils import createContentInContainer from plone.restapi.testing import PLONE_RESTAPI_DX_INTEGRATION_TESTING +from plone.restapi.tests.dxtypes import IInstanceBehaviorAssignableContent from plone.restapi.types.interfaces import IJsonSchemaProvider from plone.restapi.types.utils import get_fieldsets from plone.restapi.types.utils import get_jsonschema_for_fti @@ -18,6 +20,7 @@ from z3c.form.browser.text import TextWidget from zope import schema from zope.component import getMultiAdapter +from zope.interface import alsoProvides from zope.interface import provider from zope.schema.interfaces import IContextAwareDefaultFactory from zope.schema.vocabulary import SimpleTerm @@ -129,6 +132,29 @@ def test_get_jsonschema_for_portal_type(self): ) self.assertNotIn("title", list(jsonschema["properties"])) + def test_get_jsonschema_for_instance(self): + portal = self.portal + request = self.request + ttool = getToolByName(portal, "portal_types") + obj = createContentInContainer( + portal, + "Document", + id="doc", + title="Document", + ) + jsonschema = get_jsonschema_for_fti(ttool["Document"], obj, request) + behaviors = [field["behavior"] for field in jsonschema["properties"].values()] + self.assertIn("plone.dublincore", behaviors) + self.assertNotIn("tests.restapi.test_behavior", behaviors) + + # this testing adapter contextually add `test_behavior` and remove + # `dublincore` + alsoProvides(obj, IInstanceBehaviorAssignableContent) + jsonschema = get_jsonschema_for_fti(ttool["Document"], obj, request) + behaviors = [field["behavior"] for field in jsonschema["properties"].values()] + self.assertNotIn("plone.dublincore", behaviors) + self.assertIn("tests.restapi.test_behavior", behaviors) + class TestTaggedValuesJsonSchemaUtils(TestCase): diff --git a/src/plone/restapi/types/utils.py b/src/plone/restapi/types/utils.py index e146f9b992..3cd18a18d4 100644 --- a/src/plone/restapi/types/utils.py +++ b/src/plone/restapi/types/utils.py @@ -229,7 +229,10 @@ def get_jsonschema_for_fti(fti, context, request, excluded_fields=None): fieldsets = () additional_schemata = () else: - additional_schemata = tuple(getAdditionalSchemata(portal_type=fti.id)) + if fti.id == context.portal_type: + additional_schemata = tuple(getAdditionalSchemata(context=context)) + else: + additional_schemata = tuple(getAdditionalSchemata(portal_type=fti.id)) fieldsets = get_fieldsets(context, request, schema, additional_schemata) # Build JSON schema properties