diff --git a/docs/HISTORY.txt b/docs/HISTORY.txt index 2b0c680..5338478 100644 --- a/docs/HISTORY.txt +++ b/docs/HISTORY.txt @@ -1,6 +1,13 @@ Changelog ========= +2.0 - (2023-04-10) +--------------------------- +* Bug fix: RestAPI fix DateTime timezone for publication fields serializer/deserializer + [avoinea refs #250368] +* Cleanup: Drop Python2/Plone4 support + [avoinea refs #250368] + 1.7 - (2021-11-23) --------------------------- * Change: Removed types already present in plone.volto diff --git a/eea/volto/policy/configure.zcml b/eea/volto/policy/configure.zcml index 8e5b093..2dc0823 100644 --- a/eea/volto/policy/configure.zcml +++ b/eea/volto/policy/configure.zcml @@ -7,11 +7,10 @@ - - + diff --git a/eea/volto/policy/interfaces.py b/eea/volto/policy/interfaces.py index f9f3e2e..b3c899b 100644 --- a/eea/volto/policy/interfaces.py +++ b/eea/volto/policy/interfaces.py @@ -1,21 +1,7 @@ # -*- coding: utf-8 -*- """Module where all interfaces, events and exceptions live.""" -from eea.volto.policy import EEAMessageFactory as _ -from zope import schema -from zope.interface import Interface from zope.publisher.interfaces.browser import IDefaultBrowserLayer class IEeaVoltoPolicyLayer(IDefaultBrowserLayer): """Marker interface that defines a browser layer.""" - - -class IVoltoSettings(Interface): - """Volto settings necessary to store in the backend""" - - frontend_domain = schema.URI( - title=u"Frontend domain", - description=_(u"Used for rewriting URL's sent in thepassword reset " - u"e-mail by Plone."), - default="http://localhost:3000", - ) diff --git a/eea/volto/policy/patches.py b/eea/volto/policy/patches.py deleted file mode 100644 index 4c0f574..0000000 --- a/eea/volto/policy/patches.py +++ /dev/null @@ -1,31 +0,0 @@ -""" Patches -""" -from eea.volto.policy.interfaces import IVoltoSettings -from plone.registry.interfaces import IRegistry -from plone.rest.interfaces import IAPIRequest -from zope.component import getUtility - - -def construct_url(self, randomstring): - """Return URL used in registered_nodify_template to allow user to - change password - """ - # domain as seen by Plone backend - frontend_domain = self.portal_state().navigation_root_url() - if IAPIRequest.providedBy(self.request): - # the reset was requested through restapi, the frontend might have - # a different domain. Use volto.frontend_domain in the registry - # without triggering possible "record not found" - # Default value for volto.frontend_domain is http://localhost:3000 - - # to consider: maybe we should/could override - # @@portal_state/navigation_root_url() for - # IAPIRequest to fix this on a higher level - - registry = getUtility(IRegistry) - settings = registry.forInterface( - IVoltoSettings, prefix="volto", check=False) - frontend_domain = getattr(settings, "frontend_domain", frontend_domain) - if frontend_domain.endswith("/"): - frontend_domain = frontend_domain[:-1] - return "%s/passwordreset/%s" % (frontend_domain, randomstring) diff --git a/eea/volto/policy/patches.zcml b/eea/volto/policy/patches.zcml deleted file mode 100644 index e5f7b89..0000000 --- a/eea/volto/policy/patches.zcml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/eea/volto/policy/profiles.zcml b/eea/volto/policy/profiles.zcml index 388ecc5..66ddd3f 100644 --- a/eea/volto/policy/profiles.zcml +++ b/eea/volto/policy/profiles.zcml @@ -8,7 +8,6 @@ - - - - - diff --git a/eea/volto/policy/profiles/default/controlpanel.xml b/eea/volto/policy/profiles/default/controlpanel.xml deleted file mode 100644 index f58682c..0000000 --- a/eea/volto/policy/profiles/default/controlpanel.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - Manage portal - - diff --git a/eea/volto/policy/profiles/default/metadata.xml b/eea/volto/policy/profiles/default/metadata.xml index ce5ae4d..38ddfac 100644 --- a/eea/volto/policy/profiles/default/metadata.xml +++ b/eea/volto/policy/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 1.0 + 2.0 profile-plone.volto:default diff --git a/eea/volto/policy/profiles/default/registry.xml b/eea/volto/policy/profiles/default/registry.xml deleted file mode 100644 index dc867b2..0000000 --- a/eea/volto/policy/profiles/default/registry.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - False - - - - - False - - - - - diff --git a/eea/volto/policy/profiles/plone4/browserlayer.xml b/eea/volto/policy/profiles/plone4/browserlayer.xml deleted file mode 100644 index f417274..0000000 --- a/eea/volto/policy/profiles/plone4/browserlayer.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/eea/volto/policy/profiles/plone4/catalog.xml b/eea/volto/policy/profiles/plone4/catalog.xml deleted file mode 100644 index cb24301..0000000 --- a/eea/volto/policy/profiles/plone4/catalog.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/eea/volto/policy/profiles/plone4/controlpanel.xml b/eea/volto/policy/profiles/plone4/controlpanel.xml deleted file mode 100644 index 9ae34ba..0000000 --- a/eea/volto/policy/profiles/plone4/controlpanel.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Manage portal - - - \ No newline at end of file diff --git a/eea/volto/policy/profiles/plone4/metadata.xml b/eea/volto/policy/profiles/plone4/metadata.xml deleted file mode 100644 index e769450..0000000 --- a/eea/volto/policy/profiles/plone4/metadata.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - 1.0 - - profile-collective.folderishtypes.dx:default - profile-plone.restapi:blocks - - \ No newline at end of file diff --git a/eea/volto/policy/profiles/plone4/registry.xml b/eea/volto/policy/profiles/plone4/registry.xml deleted file mode 100644 index f5e87ff..0000000 --- a/eea/volto/policy/profiles/plone4/registry.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - False - - - - - False - - - - - diff --git a/eea/volto/policy/profiles/plone4/types.xml b/eea/volto/policy/profiles/plone4/types.xml deleted file mode 100644 index f99233e..0000000 --- a/eea/volto/policy/profiles/plone4/types.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/eea/volto/policy/profiles/plone4/types/Document.xml b/eea/volto/policy/profiles/plone4/types/Document.xml deleted file mode 100644 index 62a7e17..0000000 --- a/eea/volto/policy/profiles/plone4/types/Document.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/eea/volto/policy/profiles/plone4/types/Plone_Site.xml b/eea/volto/policy/profiles/plone4/types/Plone_Site.xml deleted file mode 100644 index 6378ec4..0000000 --- a/eea/volto/policy/profiles/plone4/types/Plone_Site.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - The root object in a Plone site. - - Plone Site - CMFPlone - manage_addSite - folder_listing - False - False - - False - folder_listing - - - - - - - - - - - - - - - - - - diff --git a/eea/volto/policy/restapi/__init__.py b/eea/volto/policy/restapi/__init__.py new file mode 100644 index 0000000..37b5429 --- /dev/null +++ b/eea/volto/policy/restapi/__init__.py @@ -0,0 +1,2 @@ +""" RestAPI +""" diff --git a/eea/volto/policy/restapi/configure.zcml b/eea/volto/policy/restapi/configure.zcml new file mode 100644 index 0000000..1ac45af --- /dev/null +++ b/eea/volto/policy/restapi/configure.zcml @@ -0,0 +1,5 @@ + + + + + diff --git a/eea/volto/policy/restapi/deserializer/__init__.py b/eea/volto/policy/restapi/deserializer/__init__.py new file mode 100644 index 0000000..cc67552 --- /dev/null +++ b/eea/volto/policy/restapi/deserializer/__init__.py @@ -0,0 +1,2 @@ +""" RestAPI deserializer +""" diff --git a/eea/volto/policy/restapi/deserializer/configure.zcml b/eea/volto/policy/restapi/deserializer/configure.zcml new file mode 100644 index 0000000..a1a64f5 --- /dev/null +++ b/eea/volto/policy/restapi/deserializer/configure.zcml @@ -0,0 +1,8 @@ + + + + + diff --git a/eea/volto/policy/restapi/deserializer/dxfields.py b/eea/volto/policy/restapi/deserializer/dxfields.py new file mode 100644 index 0000000..f2e50bd --- /dev/null +++ b/eea/volto/policy/restapi/deserializer/dxfields.py @@ -0,0 +1,66 @@ +""" DXFields +""" +import dateutil +from pytz import timezone, utc +from eea.volto.policy.interfaces import IEeaVoltoPolicyLayer +from plone.app.dexterity.behaviors.metadata import IPublication +from plone.app.event.base import default_timezone +from plone.dexterity.interfaces import IDexterityContent +from plone.restapi.deserializer.dxfields import \ + DatetimeFieldDeserializer as DefaultDatetimeFieldDeserializer +from plone.restapi.interfaces import IFieldDeserializer +from z3c.form.interfaces import IDataManager +from zope.component import adapter, queryMultiAdapter +from zope.interface import implementer +from zope.schema.interfaces import IDatetime + + +@implementer(IFieldDeserializer) +@adapter(IDatetime, IDexterityContent, IEeaVoltoPolicyLayer) +class DatetimeFieldDeserializer(DefaultDatetimeFieldDeserializer): + """ DatetimeFieldDeserializer + """ + def __call__(self, value): + # PATCH + is_publication_field = self.field.interface == IPublication + if is_publication_field: + # because IPublication datamanager strips timezones + tzinfo = timezone(default_timezone()) + else: + dm = queryMultiAdapter((self.context, self.field), IDataManager) + current = dm.get() + if current is not None: + tzinfo = current.tzinfo + else: + tzinfo = None + # END OF PATCH + + # This happens when a 'null' is posted for a non-required field. + if value is None: + self.field.validate(value) + return value + + # Parse ISO 8601 string with dateutil + dt = dateutil.parser.parse(value) + + # Convert to TZ aware in UTC + if dt.tzinfo is not None: + dt = dt.astimezone(utc) + else: + dt = utc.localize(dt) + + # Convert to local TZ aware or naive UTC + if tzinfo is not None: + tz = timezone(tzinfo.zone) + value = tz.normalize(dt.astimezone(tz)) + else: + value = utc.normalize(dt.astimezone(utc)).replace(tzinfo=None) + + # if it's an IPublication field, remove timezone + # info to not break field validation + # PATCH + if is_publication_field: + value = value.replace(tzinfo=None) + # END OF PATCH + self.field.validate(value) + return value diff --git a/eea/volto/policy/restapi/serializer/__init__.py b/eea/volto/policy/restapi/serializer/__init__.py new file mode 100644 index 0000000..6da6e47 --- /dev/null +++ b/eea/volto/policy/restapi/serializer/__init__.py @@ -0,0 +1,2 @@ +""" RestAPI serializer +""" diff --git a/eea/volto/policy/restapi/serializer/configure.zcml b/eea/volto/policy/restapi/serializer/configure.zcml new file mode 100644 index 0000000..4ec2d3f --- /dev/null +++ b/eea/volto/policy/restapi/serializer/configure.zcml @@ -0,0 +1,8 @@ + + + + + diff --git a/eea/volto/policy/restapi/serializer/dxfields.py b/eea/volto/policy/restapi/serializer/dxfields.py new file mode 100644 index 0000000..e2af093 --- /dev/null +++ b/eea/volto/policy/restapi/serializer/dxfields.py @@ -0,0 +1,30 @@ +""" DXFields +""" +from eea.volto.policy.interfaces import IEeaVoltoPolicyLayer +from plone.app.dexterity.behaviors.metadata import IPublication +from plone.dexterity.interfaces import IDexterityContent +from plone.restapi.interfaces import IFieldSerializer +from plone.restapi.serializer.dxfields import DefaultFieldSerializer +from zope.component import adapter +from zope.interface import implementer +from zope.schema.interfaces import IDatetime + + +@adapter(IDatetime, IDexterityContent, IEeaVoltoPolicyLayer) +@implementer(IFieldSerializer) +class DateTimeFieldSerializer(DefaultFieldSerializer): + """ DateTimeFieldSerializer + """ + def get_value(self, default=None): + """ Get value + """ + value = getattr( + self.field.interface(self.context), self.field.__name__, default + ) + if value and self.field.interface == IPublication: + # the patch: we want the dates with full tz infos + # default value is taken from + # plone.app.dexterity.behaviors.metadata.Publication that escape + # timezone + return getattr(self.context, self.field.__name__)() + return value diff --git a/eea/volto/policy/setuphandlers.py b/eea/volto/policy/setuphandlers.py index d7dff6e..409cab3 100644 --- a/eea/volto/policy/setuphandlers.py +++ b/eea/volto/policy/setuphandlers.py @@ -1,12 +1,11 @@ """ Custom setup """ # pylint: disable = C0301 -import json import logging from Products.CMFPlone.interfaces import INonInstallable from zope.interface import implementer -from plone import api + logger = logging.getLogger("eea.volto.policy") @@ -27,337 +26,10 @@ def getNonInstallableProfiles(self): def post_install(context): """ Post install script """ - # Get default_page if any, then set blocks to plone root - portal = api.portal.get() - homepage = getattr(portal, 'default_page', None) - if homepage: - homepage = api.content.get('/' + homepage) - create_root_homepage(portal, homepage) + # Do something at the end of the installation of this package. def uninstall(context): """ Uninstall script """ - # Remove blocks information from portal - portal = api.portal.get() - portal._delProperty("blocks") - portal._delProperty("blocks_layout") - - -def create_root_homepage(portal, default_home=None): - """It takes a default object: - { - "title": "The title", - "description": "The description", - "blocks": {...}, - "blocks_layout": [...] - } - and sets it as default page in the Plone root object. - """ - if default_home: - blocks = getattr(default_home, "blocks", {}) - blocks_layout = getattr(default_home, "blocks_layout", {}) - portal.setTitle(default_home.title) - portal.setDescription(default_home.description) - - logger.info( - "Creating custom default homepage in Plone site root." - ) - else: - blocks = { - "0358abe2-b4f1-463d-a279-a63ea80daf19": {"@type": "description"}, - "07c273fc-8bfc-4e7d-a327-d513e5a945bb": {"@type": "title"}, - "2dfe8e4c-5bf6-43f1-93e1-6c320ede7226": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [ - {"length": 10, "offset": 0, "style": "BOLD"} - ], - "key": "6470b", - "text": "Disclaimer: This instance is reset every night, so all changes will be lost afterwards.", # noqa - "type": "unstyled", - } - ], - "entityMap": {}, - }, - }, - "3c881f51-f75b-4959-834a-6e1d5edc32ae": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [ - {"length": 5, "offset": 6, "style": "BOLD"} - ], - "key": "ekn3l", - "text": "user: admin", - "type": "unstyled", - } - ], - "entityMap": {}, - }, - }, - "5e1c30b1-ec6c-4dc0-9483-9768c3c416e4": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [ - {"key": 0, "length": 5, "offset": 0}, - {"key": 1, "length": 8, "offset": 455}, - ], - "inlineStyleRanges": [], - "key": "behki", - "text": "Plone is a CMS built on Python with over 19 years of experience. Plone has very interesting features that appeal to developers and users alike, such as customizable content types, hierarchical URL object traversing and a sophisticated content workflow powered by a granular permissions model. This allows you to build anything from simple websites to enterprise-grade intranets. Volto exposes all these features and communicates with Plone via its mature REST API. Volto can be esily themed and is highly customizable.", # noqa - "type": "unstyled", - } - ], - "entityMap": { - "0": { - "data": { - "href": "https://plone.org", - "rel": "nofollow", - "url": "https://plone.org/", - }, - "mutability": "MUTABLE", - "type": "LINK", - }, - "1": { - "data": { - "href": "https://github.com/plone/plone.restapi", # noqa - "url": "https://github.com/plone/plone.restapi", # noqa - }, - "mutability": "MUTABLE", - "type": "LINK", - }, - }, - }, - }, - "61cc1bc0-d4f5-4e2b-9152-79512045a4dd": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [], - "key": "9qsa4", - "text": "Demo", - "type": "header-two", - } - ], - "entityMap": {}, - }, - }, - "874049e7-629e-489a-b46c-1adf35ad40ee": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [], - "key": "9pnjr", - "text": "Happy hacking!", - "type": "unstyled", - } - ], - "entityMap": {}, - }, - }, - "942b6530-2407-420f-9c24-597adda6b2ce": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [{"key": 0, "length": 36, "offset": 39}], # noqa - "inlineStyleRanges": [], - "key": "6a248", - "text": "Last but not least, it also supports a Volto Nodejs-based backend reference API implementation that demos how other systems could also use Volto to display and create content through it.", # noqa - "type": "unstyled", - } - ], - "entityMap": { - "0": { - "data": { - "href": "https://github.com/plone/volto-reference-backend", # noqa - "url": "https://github.com/plone/volto-reference-backend", # noqa - }, - "mutability": "MUTABLE", - "type": "LINK", - } - }, - }, - }, - "9a976b8e-72ba-468a-bea8-b37a31bb386b": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [ - {"length": 12, "offset": 51, "style": "BOLD"} - ], - "key": "94arl", - "text": "You can log in and use it as admin user using these credentials:", # noqa - "type": "unstyled", - } - ], - "entityMap": {}, - }, - }, - "b3717238-448f-406e-b06f-57a9715c3326": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [{"key": 0, "length": 5, "offset": 0}], # noqa - "inlineStyleRanges": [], - "key": "1bnna", - "text": "Volto is a React-based frontend for content management systems, currently supporting three backend implementations: Plone, Guillotina and a NodeJS reference implementation.", # noqa - "type": "unstyled", - } - ], - "entityMap": { - "0": { - "data": { - "href": "https://github.com/plone/volto", - "url": "https://github.com/plone/volto", - }, - "mutability": "MUTABLE", - "type": "LINK", - } - }, - }, - }, - "c049ff8b-3e5a-4cfb-bca6-e4a6cca9be28": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [], - "key": "55n44", - "text": "You can use this site to test Volto. It runs on the master branch of Volto using latest Plone 5.2 Backend running on Python 3.", # noqa - "type": "unstyled", - } - ], - "entityMap": {}, - }, - }, - "c91f0fe9-f2e9-4a17-84a5-8e4f2678ed3c": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [ - {"length": 5, "offset": 10, "style": "BOLD"} - ], - "key": "buncq", - "text": "password: admin", - "type": "unstyled", - } - ], - "entityMap": {}, - }, - }, - "e0ca2fbc-7800-4b9b-afe5-8e42af9f5dd6": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [], - "inlineStyleRanges": [], - "key": "f0prj", - "text": "2020 - Volto Team - Plone Foundation", - "type": "unstyled", - } - ], - "entityMap": {}, - }, - }, - "effbdcdc-253c-41a7-841e-5edb3b56ce32": { - "@type": "text", - "text": { - "blocks": [ - { - "data": {}, - "depth": 0, - "entityRanges": [{"key": 0, "length": 10, "offset": 36}], # noqa - "inlineStyleRanges": [], - "key": "68rve", - "text": "Volto also supports other APIs like Guillotina, a Python resource management system, inspired by Plone and using the same basic concepts like traversal, content types and permissions model.", # noqa - "type": "unstyled", - } - ], - "entityMap": { - "0": { - "data": { - "href": "https://guillotina.io/", - "rel": "nofollow", - "url": "https://guillotina.io/", - }, - "mutability": "MUTABLE", - "type": "LINK", - } - }, - }, - }, - } - - blocks_layout = { - "items": [ - "07c273fc-8bfc-4e7d-a327-d513e5a945bb", - "0358abe2-b4f1-463d-a279-a63ea80daf19", - "b3717238-448f-406e-b06f-57a9715c3326", - "5e1c30b1-ec6c-4dc0-9483-9768c3c416e4", - "effbdcdc-253c-41a7-841e-5edb3b56ce32", - "942b6530-2407-420f-9c24-597adda6b2ce", - "61cc1bc0-d4f5-4e2b-9152-79512045a4dd", - "c049ff8b-3e5a-4cfb-bca6-e4a6cca9be28", - "9a976b8e-72ba-468a-bea8-b37a31bb386b", - "3c881f51-f75b-4959-834a-6e1d5edc32ae", - "c91f0fe9-f2e9-4a17-84a5-8e4f2678ed3c", - "2dfe8e4c-5bf6-43f1-93e1-6c320ede7226", - "874049e7-629e-489a-b46c-1adf35ad40ee", - "e0ca2fbc-7800-4b9b-afe5-8e42af9f5dd6", - ] - } - - portal.setTitle("Welcome to Volto!") - portal.setDescription("The React powered content management system") - - logger.info("Added blocks to Plone site root.") - - if not getattr(portal, "blocks", False): - portal.manage_addProperty("blocks", json.dumps(blocks), "string") - - if not getattr(portal, "blocks_layout", False): - portal.manage_addProperty( - "blocks_layout", json.dumps(blocks_layout), "string" - ) # noqa + # Do something at the end of the uninstallation of this package. diff --git a/eea/volto/policy/tests/base.py b/eea/volto/policy/tests/base.py index 277e19e..bc4296e 100644 --- a/eea/volto/policy/tests/base.py +++ b/eea/volto/policy/tests/base.py @@ -1,7 +1,6 @@ # pylint: disable = C0412 """ Base test cases """ -from Products.CMFPlone import setuphandlers from plone.testing import z2 from plone.app.testing import TEST_USER_ID from plone.app.testing import PloneSandboxLayer @@ -10,16 +9,6 @@ from plone.app.testing import setRoles -try: - # Plone 4 - from Products.CMFPlone.interfaces import IFactoryTool - assert IFactoryTool - IS_PLONE_4 = True -except ImportError: - IS_PLONE_4 = False - - - class EEAFixture(PloneSandboxLayer): """ EEA Testing Policy """ @@ -30,10 +19,6 @@ def setUpZope(self, app, configurationContext): self.loadZCML(package=eea.volto.policy) z2.installProduct(app, 'eea.volto.policy') - # Plone 4 - if IS_PLONE_4: - z2.installProduct(app, 'Products.DateRecurringIndex') - def setUpPloneSite(self, portal): """ Setup Plone @@ -48,14 +33,10 @@ def setUpPloneSite(self, portal): setRoles(portal, TEST_USER_ID, ['Manager']) # Add default Plone content - try: - applyProfile(portal, 'plone.app.contenttypes:plone-content') - except KeyError: - # BBB Plone 4 - setuphandlers.setupPortalContent(portal) + applyProfile(portal, 'plone.app.contenttypes:default') # Create testing environment - portal.invokeFactory("Folder", "sandbox", title="Sandbox") + portal.invokeFactory("Document", "sandbox", title="Sandbox") def tearDownZope(self, app): @@ -63,10 +44,6 @@ def tearDownZope(self, app): """ z2.uninstallProduct(app, 'eea.volto.policy') - # Plone 4 - if IS_PLONE_4: - z2.uninstallProduct(app, 'Products.DateRecurringIndex') - EEAFIXTURE = EEAFixture() FUNCTIONAL_TESTING = FunctionalTesting(bases=(EEAFIXTURE,), diff --git a/eea/volto/policy/upgrades/configure.zcml b/eea/volto/policy/upgrades/configure.zcml index 331c204..dfd5e54 100644 --- a/eea/volto/policy/upgrades/configure.zcml +++ b/eea/volto/policy/upgrades/configure.zcml @@ -15,4 +15,16 @@ + + + + + + diff --git a/eea/volto/policy/version.txt b/eea/volto/policy/version.txt index d3bdbdf..cd5ac03 100644 --- a/eea/volto/policy/version.txt +++ b/eea/volto/policy/version.txt @@ -1 +1 @@ -1.7 +2.0 diff --git a/setup.py b/setup.py index a6406ba..fcf3cc6 100644 --- a/setup.py +++ b/setup.py @@ -21,11 +21,9 @@ "Environment :: Web Environment", "Framework :: Plone", "Framework :: Plone :: Addon", - "Framework :: Plone :: 4.3", "Framework :: Plone :: 5.2", "Framework :: Plone :: 6.0", "Programming Language :: Python", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9",