diff --git a/CHANGES.rst b/CHANGES.rst index 22e3a0dc..cfe14f06 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,40 @@ Changelog ========= -6.1.11 (unreleased) +6.1.15 (unreleased) +------------------- + +- Nothing changed yet. + + +6.1.14 (2024-02-20) +------------------- + +- Fix in @scadenziario endpoint: return future events if afterToday criteria is set. + [cekk] +- Set base view to News Item, to do not break on Classic Plone. + [cekk] +- Change description for field sede in UnitaOrganizzativa CT. +- Fixed typo in update_note field description. + [eikichi18] + + + +6.1.13 (2024-02-08) +------------------- + +- Handle missing `show_dynamic_folders_in_footer` in registry entry. + [cekk] + + +6.1.12 (2024-02-06) +------------------- + +- Remove un-needed commit in upgrade-step. + [cekk] + + +6.1.11 (2024-01-29) ------------------- - Added new indexer, catalog index and query operation for canale_digitale_link field of Servizio CT @@ -13,6 +46,11 @@ Changelog [cekk] - Add enhancedlinks infos in File field serializer. [cekk] +- Add new flag in settings needed to choose to show or not auto-generated footer columns. + [cekk] +- Customize @navigation endpoint to expose also the new flag for frontend. + [cekk] + 6.1.10 (2024-01-16) ------------------- diff --git a/README.md b/README.md index c1580770..ab5124c1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - [Design Plone Content-types](#design-plone-content-types) - [Features](#features) -- [Compatibilità](#compatibilit%C3%A0) +- [Compatibilità](#compatibilità) - [Tipi di contenuto](#tipi-di-contenuto) - [Elenco tipi implementati](#elenco-tipi-implementati) - [Bando](#bando) @@ -30,10 +30,11 @@ - [Campi indicizzati nel SearchableText](#campi-indicizzati-nel-searchabletext-2) - [Servizio](#servizio) - [Campi indicizzati nel SearchableText](#campi-indicizzati-nel-searchabletext-3) - - [Unità Organizzativa](#unit%C3%A0-organizzativa) + - [Unità Organizzativa](#unità-organizzativa) - [Campi indicizzati nel SearchableText](#campi-indicizzati-nel-searchabletext-4) - [Pannello di controllo](#pannello-di-controllo) - [Gestione modulistica](#gestione-modulistica) +- [Viste verifica contentuti](#viste-verifica-contentuti) - [Data di modifica](#data-di-modifica) - [Endpoint restapi](#endpoint-restapi) - [Customizzazione dati relation field](#customizzazione-dati-relation-field) @@ -421,6 +422,10 @@ Endpoint ed expansion per la modulistica. Nei content-type CartellaModulistica, tra i vari expansion c'è anche `@modulistica_items`. Questo è utile per la vista di frontend, in quanto se richiamato, ritorna la struttura di dati da mostrare in visualizzazione. +## @navigation + +Endpoint customizzato da plone.restapi per esporre anche il valore show_in_footer per decidere se disegnare o meno le colonne dinamiche nel footer. + # Installazione Questo prodotto non è stato pensato per funzionare da solo, ma fa parte della suite "design.plone". diff --git a/setup.py b/setup.py index 9399e5fa..02c87c81 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( name="design.plone.contenttypes", - version="6.1.11.dev0", + version="6.1.15.dev0", description="DesignItalia contenty types", long_description=long_description, long_description_content_type="text/markdown", diff --git a/src/design/plone/contenttypes/behaviors/update_note.py b/src/design/plone/contenttypes/behaviors/update_note.py index 113fe7f1..9e1d6f5b 100644 --- a/src/design/plone/contenttypes/behaviors/update_note.py +++ b/src/design/plone/contenttypes/behaviors/update_note.py @@ -18,7 +18,7 @@ class IUpdateNote(model.Schema): description=_( "help_update_note", default="Inserisci una nota per indicare che il contenuto corrente è stato aggiornato." # noqa - "Questo testo può essere visualizzato nei blocchi elenco con determinati layout per informare " # noqa + " Questo testo può essere visualizzato nei blocchi elenco con determinati layout per informare " # noqa "gli utenti che un determinato contenuto è stato aggiornato. " "Ad esempio se in un bando sono stati aggiunti dei documenti.", ), diff --git a/src/design/plone/contenttypes/browser/overrides/plone.app.contenttypes.browser.templates.newsitem.pt b/src/design/plone/contenttypes/browser/overrides/plone.app.contenttypes.browser.templates.newsitem.pt deleted file mode 100644 index 53d14271..00000000 --- a/src/design/plone/contenttypes/browser/overrides/plone.app.contenttypes.browser.templates.newsitem.pt +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -
-
-
- - - diff --git a/src/design/plone/contenttypes/controlpanels/settings.py b/src/design/plone/contenttypes/controlpanels/settings.py index 60beed41..365b8135 100644 --- a/src/design/plone/contenttypes/controlpanels/settings.py +++ b/src/design/plone/contenttypes/controlpanels/settings.py @@ -88,6 +88,16 @@ class IDesignPloneSettings(Interface): default=True, required=False, ) + show_dynamic_folders_in_footer = Bool( + title=_("show_dynamic_folders_in_footer_label", default="Footer dinamico"), + description=_( + "show_dynamic_folders_in_footer_help", + default="Se selezionato, il footer verrà popolato automaticamente " + "con i contenuti di primo livello non esclusi dalla navigazione.", + ), + default=True, + required=False, + ) class DesignPloneControlPanelForm(RegistryEditForm): diff --git a/src/design/plone/contenttypes/interfaces/unita_organizzativa.py b/src/design/plone/contenttypes/interfaces/unita_organizzativa.py index 12e1bfad..b54570f1 100644 --- a/src/design/plone/contenttypes/interfaces/unita_organizzativa.py +++ b/src/design/plone/contenttypes/interfaces/unita_organizzativa.py @@ -97,10 +97,8 @@ class IUnitaOrganizzativa(model.Schema, IDesignPloneContentType): description=_( "sede_help", default="Seleziona il Luogo in cui questa struttura ha sede. " - "Se non è presente un contenuto di tipo Luogo a cui far " - "riferimento, puoi compilare i campi seguenti. Se selezioni un " - "Luogo, puoi usare comunque i campi seguenti per sovrascrivere " - "alcune informazioni.", + "Se non è presente creare il Luogo nella sezione dedicata " + "nell'alberatura del sito.", ), value_type=RelationChoice( title=_("Sede"), vocabulary="plone.app.vocabularies.Catalog" diff --git a/src/design/plone/contenttypes/profiles/default/metadata.xml b/src/design/plone/contenttypes/profiles/default/metadata.xml index 715b70fe..d0c46e17 100644 --- a/src/design/plone/contenttypes/profiles/default/metadata.xml +++ b/src/design/plone/contenttypes/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 7030 + 7040 profile-redturtle.bandi:default profile-collective.venue:default diff --git a/src/design/plone/contenttypes/profiles/default/types/Document.xml b/src/design/plone/contenttypes/profiles/default/types/Document.xml index 56036477..30e528d3 100644 --- a/src/design/plone/contenttypes/profiles/default/types/Document.xml +++ b/src/design/plone/contenttypes/profiles/default/types/Document.xml @@ -4,6 +4,7 @@ name="Document" i18n:domain="plone" > + diff --git a/src/design/plone/contenttypes/profiles/default/types/Event.xml b/src/design/plone/contenttypes/profiles/default/types/Event.xml index 412101c9..5edb1552 100644 --- a/src/design/plone/contenttypes/profiles/default/types/Event.xml +++ b/src/design/plone/contenttypes/profiles/default/types/Event.xml @@ -14,6 +14,7 @@ + diff --git a/src/design/plone/contenttypes/profiles/default/types/News_Item.xml b/src/design/plone/contenttypes/profiles/default/types/News_Item.xml index 1c0f6d9b..0da6ce08 100644 --- a/src/design/plone/contenttypes/profiles/default/types/News_Item.xml +++ b/src/design/plone/contenttypes/profiles/default/types/News_Item.xml @@ -17,6 +17,11 @@ + view + + + + diff --git a/src/design/plone/contenttypes/restapi/services/configure.zcml b/src/design/plone/contenttypes/restapi/services/configure.zcml index 06d609df..e93dcc9d 100644 --- a/src/design/plone/contenttypes/restapi/services/configure.zcml +++ b/src/design/plone/contenttypes/restapi/services/configure.zcml @@ -6,9 +6,11 @@ + - + + + + + + + + diff --git a/src/design/plone/contenttypes/restapi/services/navigation/get.py b/src/design/plone/contenttypes/restapi/services/navigation/get.py new file mode 100644 index 00000000..73550281 --- /dev/null +++ b/src/design/plone/contenttypes/restapi/services/navigation/get.py @@ -0,0 +1,32 @@ +from design.plone.contenttypes.controlpanels.settings import IDesignPloneSettings +from design.plone.contenttypes.interfaces import IDesignPloneContenttypesLayer +from plone import api +from plone.restapi.interfaces import IExpandableElement +from plone.restapi.services import Service +from plone.restapi.services.navigation.get import Navigation as BaseNavigation +from zope.component import adapter +from zope.interface import implementer +from zope.interface import Interface + + +@implementer(IExpandableElement) +@adapter(Interface, IDesignPloneContenttypesLayer) +class Navigation(BaseNavigation): + def __call__(self, expand=False): + result = super().__call__(expand=expand) + try: + show_dynamic_folders_in_footer = api.portal.get_registry_record( + "show_dynamic_folders_in_footer", + interface=IDesignPloneSettings, + default=True, + ) + except KeyError: + show_dynamic_folders_in_footer = True + result["navigation"]["show_in_footer"] = show_dynamic_folders_in_footer + return result + + +class NavigationGet(Service): + def reply(self): + navigation = Navigation(self.context, self.request) + return navigation(expand=True)["navigation"] diff --git a/src/design/plone/contenttypes/restapi/services/scadenziario/post.py b/src/design/plone/contenttypes/restapi/services/scadenziario/post.py index 07ba6299..e19720c1 100644 --- a/src/design/plone/contenttypes/restapi/services/scadenziario/post.py +++ b/src/design/plone/contenttypes/restapi/services/scadenziario/post.py @@ -158,7 +158,13 @@ def reply(self): if "start" in query_for_catalog: start = query_for_catalog["start"]["query"] if "end" in query_for_catalog: - end = query_for_catalog["end"]["query"] + if query_for_catalog["end"].get("range", "") != "min": + # per esempio, è impostato il filtro "con fine evento da domani". + # se impostiamo un'end (la data di domani), poi nella generazione delle ricorrenze, + # vengono scartati tutti gli eventi che hanno una data di inizio nel futuro + # (https://github.com/plone/plone.event/blob/master/plone/event/recurrence.py#L141) + # perché la data della ricorrenza è maggiore di "until", che è quello che qui inviamo come end. + end = query_for_catalog["end"]["query"] expanded_events = self.expand_events(events, 3, start, end) all_results = not_events + expanded_events diff --git a/src/design/plone/contenttypes/tests/test_custom_service_navigation.py b/src/design/plone/contenttypes/tests/test_custom_service_navigation.py new file mode 100644 index 00000000..014ad580 --- /dev/null +++ b/src/design/plone/contenttypes/tests/test_custom_service_navigation.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +from design.plone.contenttypes.controlpanels.settings import IDesignPloneSettings +from design.plone.contenttypes.testing import ( + DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, +) +from plone import api +from plone.app.testing import setRoles +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_ID +from plone.dexterity.utils import createContentInContainer +from plone.restapi.testing import RelativeSession +from transaction import commit + +import unittest + + +class CustomNavigationTest(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING + + def setUp(self): + self.app = self.layer["app"] + self.portal = self.layer["portal"] + self.portal_url = self.portal.absolute_url() + self.api_session = RelativeSession(self.portal_url) + self.api_session.headers.update({"Accept": "application/json"}) + self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + self.folder = createContentInContainer( + self.portal, "Folder", id="folder", title="Some Folder" + ) + self.folder2 = createContentInContainer( + self.portal, "Folder", id="folder2", title="Some Folder 2" + ) + self.subfolder1 = createContentInContainer( + self.folder, "Folder", id="subfolder1", title="SubFolder 1" + ) + self.subfolder2 = createContentInContainer( + self.folder, "Folder", id="subfolder2", title="SubFolder 2" + ) + self.thirdlevelfolder = createContentInContainer( + self.subfolder1, + "Folder", + id="thirdlevelfolder", + title="Third Level Folder", + ) + self.fourthlevelfolder = createContentInContainer( + self.thirdlevelfolder, + "Folder", + id="fourthlevelfolder", + title="Fourth Level Folder", + ) + createContentInContainer(self.folder, "Document", id="doc1", title="A document") + commit() + + def tearDown(self): + self.api_session.close() + + def test_return_show_in_footer_info_based_on_registry(self): + # by default is True + response = self.api_session.get( + "/@navigation", params={"expand.navigation.depth": 2} + ).json() + + self.assertIn("show_in_footer", response) + self.assertTrue(response["show_in_footer"]) + + # change it + api.portal.set_registry_record( + "show_dynamic_folders_in_footer", + False, + interface=IDesignPloneSettings, + ) + commit() + + response = self.api_session.get( + "/@navigation", params={"expand.navigation.depth": 2} + ).json() + + self.assertIn("show_in_footer", response) + self.assertFalse(response["show_in_footer"]) diff --git a/src/design/plone/contenttypes/tests/test_service_scadenziario.py b/src/design/plone/contenttypes/tests/test_service_scadenziario.py new file mode 100644 index 00000000..bdc56425 --- /dev/null +++ b/src/design/plone/contenttypes/tests/test_service_scadenziario.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +from datetime import datetime +from datetime import timedelta +from design.plone.contenttypes.testing import ( + DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, +) +from plone import api +from plone.app.testing import setRoles +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.app.testing import TEST_USER_ID +from plone.restapi.testing import RelativeSession +from transaction import commit + +import unittest + + +class ScadenziarioTest(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING + + def setUp(self): + self.app = self.layer["app"] + self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + + self.api_session = RelativeSession(self.portal_url) + self.api_session.headers.update({"Accept": "application/json"}) + self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) + + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + commit() + + def tearDown(self): + self.api_session.close() + + def test_return_future_events_if_query_is_end_after_today(self): + now = datetime.now() + + # past event + api.content.create( + container=self.portal, + type="Event", + title="Past event", + start=now.replace(hour=8) + timedelta(days=-2), + end=now.replace(hour=18) + timedelta(days=-2), + ) + + future_event_1 = api.content.create( + container=self.portal, + type="Event", + title="Future event", + start=now.replace(hour=8) + timedelta(days=2), + end=now.replace(hour=18) + timedelta(days=4), + ) + future_event_2 = api.content.create( + container=self.portal, + type="Event", + title="Future event that starts in the past", + start=now.replace(hour=8) + timedelta(days=-4), + end=now.replace(hour=18) + timedelta(days=4), + ) + + commit() + + response = self.api_session.post( + f"{self.portal_url}/@scadenziario", + json={ + "query": [ + { + "i": "end", + "o": "plone.app.querystring.operation.date.afterToday", + "v": "", + } + ] + }, + ).json() + self.assertEqual(len(response["items"]), 2) + + # results are in asc order + self.assertEqual( + response["items"][0], + future_event_2.start.strftime("%Y/%m/%d"), + ) + self.assertEqual( + response["items"][1], + future_event_1.start.strftime("%Y/%m/%d"), + ) diff --git a/src/design/plone/contenttypes/upgrades/configure.zcml b/src/design/plone/contenttypes/upgrades/configure.zcml index 0c113620..fc780738 100644 --- a/src/design/plone/contenttypes/upgrades/configure.zcml +++ b/src/design/plone/contenttypes/upgrades/configure.zcml @@ -810,12 +810,22 @@ + + + - + \ No newline at end of file diff --git a/src/design/plone/contenttypes/upgrades/upgrades.py b/src/design/plone/contenttypes/upgrades/upgrades.py index 71c8cd3a..c34b734b 100644 --- a/src/design/plone/contenttypes/upgrades/upgrades.py +++ b/src/design/plone/contenttypes/upgrades/upgrades.py @@ -1576,8 +1576,6 @@ def update_pdc_with_pdc_desc(context): logger.info(f"Set pdc_desc for {pdc.absolute_url()}") pdc.value_punto_contatto = value_punto_contatto - - commit() logger.info("Ends of update") @@ -1611,3 +1609,10 @@ def add_canale_digitale_link_index(context): service.reindexObject(idxs=["canale_digitale_link"]) logger.info(f"Reindexed {service.absolute_url()}") logger.info("End of update, added index canale_digitale_link") + + +def to_7031(context): + portal_types = api.portal.get_tool(name="portal_types") + for ptype in ["News Item"]: + portal_types[ptype].default_view = "view" + portal_types[ptype].view_methods = ["view"]