From cea20d688cb5877355acb6a499a873b08b0286c2 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Fri, 13 Oct 2023 10:03:38 +0200 Subject: [PATCH 01/23] improved tests --- .../plone/contenttypes/tests/test_ct_bando.py | 174 +++++++++++ .../tests/test_ct_cartella_modulistica.py | 135 ++++++++- .../contenttypes/tests/test_ct_document.py | 160 +++++++++- .../contenttypes/tests/test_ct_documento.py | 184 +++++++++++- .../tests/test_ct_documento_personale.py | 39 --- .../plone/contenttypes/tests/test_ct_event.py | 275 +++++++++++++++++- .../plone/contenttypes/tests/test_ct_luogo.py | 213 +++++++++++++- .../contenttypes/tests/test_ct_modulo.py | 108 ++++++- .../plone/contenttypes/tests/test_ct_news.py | 154 +++++++++- .../tests/test_ct_pagina_argomento.py | 147 +++++++++- .../contenttypes/tests/test_ct_persona.py | 200 +++++++++++-- .../contenttypes/tests/test_ct_servizio.py | 273 ++++++++++++++++- .../tests/test_ct_unita_organizzativa.py | 269 ++++++++++++++--- 13 files changed, 2171 insertions(+), 160 deletions(-) delete mode 100644 src/design/plone/contenttypes/tests/test_ct_documento_personale.py diff --git a/src/design/plone/contenttypes/tests/test_ct_bando.py b/src/design/plone/contenttypes/tests/test_ct_bando.py index a11587df..ddb628c4 100644 --- a/src/design/plone/contenttypes/tests/test_ct_bando.py +++ b/src/design/plone/contenttypes/tests/test_ct_bando.py @@ -1,15 +1,189 @@ # -*- coding: utf-8 -*- from design.plone.contenttypes.testing import ( DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, + DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) from plone import api from plone.app.testing import setRoles from plone.app.testing import TEST_USER_ID +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.restapi.testing import RelativeSession from redturtle.bandi.interfaces.settings import IBandoSettings import unittest +class TestBandoSchema(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() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() + + def test_behaviors_enabled_for_bando(self): + portal_types = api.portal.get_tool(name="portal_types") + self.assertEqual( + portal_types["Bando"].behaviors, + ( + "plone.app.content.interfaces.INameFromTitle", + "plone.app.dexterity.behaviors.discussion.IAllowDiscussion", + "plone.app.dexterity.behaviors.exclfromnav.IExcludeFromNavigation", + "plone.app.dexterity.behaviors.id.IShortName", + "plone.app.dexterity.behaviors.metadata.IDublinCore", + "plone.app.relationfield.behavior.IRelatedItems", + "plone.app.versioningbehavior.behaviors.IVersionable", + "plone.app.contenttypes.behaviors.tableofcontents.ITableOfContents", + "plone.app.lockingbehavior.behaviors.ILocking", + "Products.CMFPlone.interfaces.constrains.ISelectableConstrainTypes", + "plone.versioning", + "design.plone.contenttypes.behavior.argomenti_bando", + "plone.textindexer", + "plone.translatable", + "kitconcept.seo", + "design.plone.contenttypes.behavior.update_note", + "volto.preview_image", + ), + ) + + def test_bando_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual(len(resp["fieldsets"]), 7) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "correlati", + "settings", + "categorization", + "dates", + "ownership", + "seo", + ], + ) + + def test_bando_required_fields(self): + resp = self.api_session.get("@types/Bando").json() + self.assertEqual( + sorted(resp["required"]), + sorted(["title", "tipologia_bando"]), + ) + + def test_bando_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "text", + "tipologia_bando", + "destinatari", + "ente_bando", + "apertura_bando", + "scadenza_domande_bando", + "scadenza_bando", + "chiusura_procedimento_bando", + "riferimenti_bando", + "update_note", + "preview_image", + "preview_caption", + ], + ) + + def test_bando_fields_correlati_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + [ + "area_responsabile", + "ufficio_responsabile", + "tassonomia_argomenti", + "correlato_in_evidenza", + ], + ) + + def test_bando_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "table_of_contents", + "changeNote", + ], + ) + + def test_bando_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], + ["subjects", "language", "relatedItems"], + ) + + def test_bando_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual(resp["fieldsets"][4]["fields"], ["effective", "expires"]) + + def test_bando_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual( + resp["fieldsets"][5]["fields"], ["creators", "contributors", "rights"] + ) + + def test_bando_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Bando").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) + + class TestBando(unittest.TestCase): layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING diff --git a/src/design/plone/contenttypes/tests/test_ct_cartella_modulistica.py b/src/design/plone/contenttypes/tests/test_ct_cartella_modulistica.py index fe0047e7..69c19a9a 100644 --- a/src/design/plone/contenttypes/tests/test_ct_cartella_modulistica.py +++ b/src/design/plone/contenttypes/tests/test_ct_cartella_modulistica.py @@ -1,21 +1,36 @@ # -*- coding: utf-8 -*- from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, + DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) from plone import api +from plone.app.testing import setRoles +from plone.app.testing import TEST_USER_ID +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.restapi.testing import RelativeSession import unittest -class TestCartellaModulistica(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestCartellaModulisticaSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) - def test_behaviors_enabled_for_documento(self): + 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) + + def tearDown(self): + self.api_session.close() + + def test_behaviors_enabled_for_cartella_modulistica(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual( portal_types["CartellaModulistica"].behaviors, @@ -38,9 +53,117 @@ def test_behaviors_enabled_for_documento(self): ), ) - def test_event_addable_types(self): + def test_cartella_modulistica_addable_types(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual( ("Document", "Documento", "Link", "Image", "File"), portal_types["CartellaModulistica"].allowed_content_types, ) + + def test_cartella_modulistica_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual(len(resp["fieldsets"]), 7) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "settings", + "ownership", + "dates", + "categorization", + "layout", + "seo", + ], + ) + + def test_cartella_modulistica_required_fields(self): + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual( + sorted(resp["required"]), + sorted(["title"]), + ) + + def test_cartella_modulistica_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "visualize_files", + "image", + "image_caption", + "preview_image", + "preview_caption", + ], + ) + + def test_cartella_modulistica_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "changeNote", + ], + ) + + def test_cartella_modulistica_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], ["creators", "contributors", "rights"] + ) + + def test_cartella_modulistica_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual(resp["fieldsets"][3]["fields"], ["effective", "expires"]) + + def test_cartella_modulistica_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual(resp["fieldsets"][4]["fields"], ["subjects", "language"]) + + def test_cartella_modulistica_fields_layout_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual(resp["fieldsets"][5]["fields"], ["blocks", "blocks_layout"]) + + def test_cartella_modulistica_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/CartellaModulistica").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) diff --git a/src/design/plone/contenttypes/tests/test_ct_document.py b/src/design/plone/contenttypes/tests/test_ct_document.py index 162a3459..3262761c 100644 --- a/src/design/plone/contenttypes/tests/test_ct_document.py +++ b/src/design/plone/contenttypes/tests/test_ct_document.py @@ -1,19 +1,34 @@ # -*- coding: utf-8 -*- from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, + DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) from plone import api +from plone.app.testing import setRoles +from plone.app.testing import TEST_USER_ID +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.restapi.testing import RelativeSession import unittest -class TestDocument(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestDocumentSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() def test_behaviors_enabled_for_document(self): portal_types = api.portal.get_tool(name="portal_types") @@ -39,3 +54,140 @@ def test_behaviors_enabled_for_document(self): "volto.preview_image", ), ) + + def test_document_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual(len(resp["fieldsets"]), 9) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "testata", + "settings", + "correlati", + "categorization", + "dates", + "ownership", + "layout", + "seo", + ], + ) + + def test_document_required_fields(self): + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + sorted(resp["required"]), + sorted(["title"]), + ) + + def test_document_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + ], + ) + + def test_document_fields_testata_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + [ + "image", + "image_caption", + "preview_image", + "ricerca_in_testata", + "mostra_bottoni_condivisione", + "info_testata", + "mostra_navigazione", + "tassonomia_argomenti", + ], + ) + + def test_document_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "show_modified", + "changeNote", + ], + ) + + def test_document_fields_correlati_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], + ["correlato_in_evidenza"], + ) + + def test_document_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], ["subjects", "language", "relatedItems"] + ) + + def test_document_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual(resp["fieldsets"][5]["fields"], ["effective", "expires"]) + + def test_document_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], ["creators", "contributors", "rights"] + ) + + def test_document_fields_layout_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual(resp["fieldsets"][7]["fields"], ["blocks", "blocks_layout"]) + + def test_document_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Document").json() + self.assertEqual( + resp["fieldsets"][8]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) diff --git a/src/design/plone/contenttypes/tests/test_ct_documento.py b/src/design/plone/contenttypes/tests/test_ct_documento.py index 996b4400..d5d7f207 100644 --- a/src/design/plone/contenttypes/tests/test_ct_documento.py +++ b/src/design/plone/contenttypes/tests/test_ct_documento.py @@ -3,9 +3,6 @@ from design.plone.contenttypes.testing import ( DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) -from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, -) from plone import api from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME @@ -19,13 +16,23 @@ import unittest -class TestDocument(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestDocumentoSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING maxDiff = None def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() def test_behaviors_enabled_for_documento(self): portal_types = api.portal.get_tool(name="portal_types") @@ -43,7 +50,7 @@ def test_behaviors_enabled_for_documento(self): "plone.leadimage", "volto.preview_image", "design.plone.contenttypes.behavior.argomenti_documento", - "design.plone.contenttypes.behavior.descrizione_estesa_documento", # noqa + "design.plone.contenttypes.behavior.descrizione_estesa_documento", "design.plone.contenttypes.behavior.additional_help_infos", "plone.textindexer", "plone.translatable", @@ -57,13 +64,174 @@ def test_behaviors_enabled_for_documento(self): ), ) - def test_event_addable_types(self): + def test_documento_addable_types(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual( ("Document", "Modulo", "Link"), portal_types["Documento"].allowed_content_types, ) + def test_documento_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual(len(resp["fieldsets"]), 9) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "descrizione", + "informazioni", + "settings", + "correlati", + "categorization", + "dates", + "ownership", + "seo", + ], + ) + + def test_documento_required_fields(self): + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + "formati_disponibili", + "tassonomia_argomenti", + "tipologia_documento", + "ufficio_responsabile", + "tipologia_licenze", + "description", + ] + ), + ) + + def test_documento_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "identificativo", + "protocollo", + "data_protocollo", + "formati_disponibili", + "dataset", + "image", + "image_caption", + "preview_image", + "preview_caption", + "tassonomia_argomenti", + "person_life_events", + "business_events", + "tipologia_documenti_albopretorio", + "tipologia_documento", + ], + ) + + def test_documento_fields_descrizione_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + [ + "ufficio_responsabile", + "area_responsabile", + "autori", + "licenza_distribuzione", + "descrizione_estesa", + "tipologia_licenze", + ], + ) + + def test_documento_fields_informazioni_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + ["riferimenti_normativi", "documenti_allegati", "ulteriori_informazioni"], + ) + + def test_documento_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "changeNote", + ], + ) + + def test_documento_fields_correlati_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + ["correlato_in_evidenza"], + ) + + def test_documento_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][5]["fields"], ["subjects", "language", "relatedItems"] + ) + + def test_documento_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual(resp["fieldsets"][6]["fields"], ["effective", "expires"]) + + def test_documento_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][7]["fields"], ["creators", "contributors", "rights"] + ) + + def test_documento_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Documento").json() + self.assertEqual( + resp["fieldsets"][8]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) + class TestDocumentoApi(unittest.TestCase): layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING diff --git a/src/design/plone/contenttypes/tests/test_ct_documento_personale.py b/src/design/plone/contenttypes/tests/test_ct_documento_personale.py deleted file mode 100644 index 75e0fa56..00000000 --- a/src/design/plone/contenttypes/tests/test_ct_documento_personale.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- - -from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, -) -from plone import api - -import unittest - - -class TestDocument(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING - - def setUp(self): - """Custom shared utility setup for tests.""" - self.portal = self.layer["portal"] - - def test_behaviors_enabled_for_documento_personale(self): - portal_types = api.portal.get_tool(name="portal_types") - self.assertEqual( - portal_types["Documento Personale"].behaviors, - ( - "plone.namefromtitle", - "plone.allowdiscussion", - "plone.excludefromnavigation", - "plone.shortname", - "plone.ownership", - "plone.publication", - "plone.categorization", - "plone.basic", - "design.plone.contenttypes.behavior.descrizione_estesa", - "design.plone.contenttypes.behavior.additional_help_infos", - "plone.locking", - ), - ) - - def test_document_ct_title(self): - portal_types = api.portal.get_tool(name="portal_types") - self.assertEqual("Documento", portal_types["Documento"].title) diff --git a/src/design/plone/contenttypes/tests/test_ct_event.py b/src/design/plone/contenttypes/tests/test_ct_event.py index b675f551..a0a527e8 100644 --- a/src/design/plone/contenttypes/tests/test_ct_event.py +++ b/src/design/plone/contenttypes/tests/test_ct_event.py @@ -4,9 +4,6 @@ from design.plone.contenttypes.testing import ( DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) -from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, -) from plone import api from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME @@ -20,13 +17,23 @@ import unittest -class TestEvent(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestEventSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING maxDiff = None def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() def test_behaviors_enabled_for_event(self): portal_types = api.portal.get_tool(name="portal_types") @@ -73,6 +80,262 @@ def test_event_provide_design_pct_marker_interface(self): event = api.content.create(container=self.portal, type="Event", title="Evento") self.assertTrue(IDesignPloneContentType.providedBy(event)) + def test_event_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual(len(resp["fieldsets"]), 12) + # should be 13 but SchemaTweaks does not work in tests + # self.assertEqual(len(resp["fieldsets"]), 13) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "cose", + "luogo", + "date_e_orari", + "costi", + "contatti", + "informazioni", + # "correlati", see SchemaTweaks problem in tests + "categorization", + "dates", + "settings", + "ownership", + "seo", + ], + ) + + def test_event_required_fields(self): + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + "tassonomia_argomenti", + "tipologia_evento", + "start", + "end", + "descrizione_estesa", + "descrizione_destinatari", + "contact_info", + "description", + ] + ), + ) + + def test_event_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "start", + "end", + "whole_day", + "open_end", + "sync_uid", + "image", + "image_caption", + "preview_image", + "preview_caption", + "correlato_in_evidenza", + "tassonomia_argomenti", + "recurrence", + "sottotitolo", + "tipologia_evento", + ] + # should be like this with SchemaTweaks + # [ + # "title", + # "description", + # "image", + # "image_caption", + # "preview_image", + # "preview_caption", + # "correlato_in_evidenza", + # "tassonomia_argomenti", + # "sottotitolo", + # "tipologia_evento", + # ], + ) + + def test_event_fields_cose_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + [ + "descrizione_estesa", + "descrizione_destinatari", + "persone_amministrazione", + ], + ) + + def test_event_fields_luogo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + [ + "luoghi_correlati", + "nome_sede", + "street", + "zip_code", + "city", + "quartiere", + "circoscrizione", + "country", + "geolocation", + ], + ) + + def test_event_fields_date_e_orari_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], + [ + "orari", + ], + # with SchemaTweaks should be like this + # [ + # "start", + # "end", + # "whole_day", + # "open_end", + # "sync_uid", + # "recurrence", + # "orari", + # ], + ) + + def test_event_fields_costi_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + [ + "prezzo", + ], + # should be like this with SchemaTweaks + # [ + # "costi", + # ], + ) + + def test_event_fields_contatti_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][5]["fields"], + [ + "organizzato_da_interno", + "organizzato_da_esterno", + "supportato_da", + "patrocinato_da", + "contact_info", + ], + ) + + def test_event_fields_informazioni_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], + ["ulteriori_informazioni", "strutture_politiche"], + ) + + # def test_event_fields_correlati_fieldset(self): + # """ + # Get the list from restapi + # """ + # resp = self.api_session.get("@types/Event").json() + # self.assertEqual( + # resp["fieldsets"][7]["fields"], + # ["relatedItems"], + # ) + + def test_event_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][7]["fields"], + ["subjects", "language", "relatedItems"] + # should be like this with SchemaTweaks + # ["subjects", "language"], + ) + + def test_event_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual(resp["fieldsets"][8]["fields"], ["effective", "expires"]) + + def test_event_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][9]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "changeNote", + ], + ) + + def test_event_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][10]["fields"], ["creators", "contributors", "rights"] + ) + + def test_event_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Event").json() + self.assertEqual( + resp["fieldsets"][11]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) + class TestEventApi(unittest.TestCase): layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING diff --git a/src/design/plone/contenttypes/tests/test_ct_luogo.py b/src/design/plone/contenttypes/tests/test_ct_luogo.py index fef1180b..b2ab7ea6 100644 --- a/src/design/plone/contenttypes/tests/test_ct_luogo.py +++ b/src/design/plone/contenttypes/tests/test_ct_luogo.py @@ -3,9 +3,6 @@ from design.plone.contenttypes.testing import ( DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) -from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, -) from plone import api from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME @@ -22,13 +19,22 @@ import unittest -class TestLuogo(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING - maxDiff = None +class TestLuogoSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() def test_behaviors_enabled_for_luogo(self): portal_types = api.portal.get_tool(name="portal_types") @@ -62,6 +68,199 @@ def test_luogo_ct_title(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual("Luogo", portal_types["Venue"].title) + def test_luogo_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual(len(resp["fieldsets"]), 11) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "descrizione", + "accesso", + "dove", + "orari", + "contatti", + "informazioni", + "settings", + "correlati", + "categorization", + "seo", + ], + ) + + def test_luogo_required_fields(self): + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + "contact_info", + "modalita_accesso", + "description", + "image", + "street", + "city", + "zip_code", + "geolocation", + ] + ), + ) + + def test_luogo_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "image", + "image_caption", + "preview_image", + "preview_caption", + "nome_alternativo", + "tassonomia_argomenti", + "luoghi_correlati", + "tipologia_luogo", + ], + ) + + def test_luogo_fields_descrizione_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + ["descrizione_completa", "elementi_di_interesse"], + ) + + def test_luogo_fields_accesso_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + ["modalita_accesso"], + ) + + def test_luogo_fields_dove_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], + [ + "street", + "zip_code", + "city", + "quartiere", + "circoscrizione", + "country", + "geolocation", + "notes", + ], + ) + + def test_luogo_fields_orari_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + ["orario_pubblico"], + ) + + def test_luogo_fields_contatti_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][5]["fields"], + [ + "contact_info", + "struttura_responsabile_correlati", + "struttura_responsabile", + ], + ) + + def test_luogo_fields_informazioni_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], + [ + "ulteriori_informazioni", + ], + ) + + def test_luogo_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][7]["fields"], + [ + "id", + "exclude_from_nav", + "versioning_enabled", + "changeNote", + ], + ) + + def test_luogo_fields_correlati_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][8]["fields"], + ["correlato_in_evidenza"], + ) + + def test_luogo_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][9]["fields"], + # ["subjects", "language", "identificativo_mibac"] BBB dovrebbe essere così + # ma nei test esce così perché non viene vista la patch di SchemaTweaks + ["subjects", "language", "relatedItems", "identificativo_mibac"], + ) + + def test_luogo_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Venue").json() + self.assertEqual( + resp["fieldsets"][10]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) + class TestLuogoApi(unittest.TestCase): layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING diff --git a/src/design/plone/contenttypes/tests/test_ct_modulo.py b/src/design/plone/contenttypes/tests/test_ct_modulo.py index e12bf364..5ff31e7d 100644 --- a/src/design/plone/contenttypes/tests/test_ct_modulo.py +++ b/src/design/plone/contenttypes/tests/test_ct_modulo.py @@ -1,21 +1,36 @@ # -*- coding: utf-8 -*- from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, + DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) from plone import api +from plone.app.testing import setRoles +from plone.app.testing import TEST_USER_ID +from plone.app.testing import SITE_OWNER_NAME +from plone.app.testing import SITE_OWNER_PASSWORD +from plone.restapi.testing import RelativeSession import unittest -class TestDocument(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestModuloSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) - def test_behaviors_enabled_for_documento(self): + 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) + + def tearDown(self): + self.api_session.close() + + def test_behaviors_enabled_for_modulo(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual( portal_types["Modulo"].behaviors, @@ -31,3 +46,86 @@ def test_behaviors_enabled_for_documento(self): "plone.translatable", ), ) + + def test_modulo_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Modulo").json() + self.assertEqual(len(resp["fieldsets"]), 5) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "settings", + # "correlati", + "categorization", + "dates", + "ownership", + ], + ) + + def test_modulo_required_fields(self): + resp = self.api_session.get("@types/Modulo").json() + self.assertEqual( + sorted(resp["required"]), + sorted(["title", "file_principale"]), + ) + + def test_modulo_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Modulo").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "file_principale", + "formato_alternativo_1", + "formato_alternativo_2", + ], + ) + + def test_modulo_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Modulo").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + ], + ) + + def test_modulo_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Modulo").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + # ["subjects", "language"] BBB dovrebbe essere così + # ma nei test esce così perché non viene vista la patch di SchemaTweaks + ["subjects", "language", "relatedItems"], + ) + + def test_modulo_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Modulo").json() + self.assertEqual(resp["fieldsets"][3]["fields"], ["effective", "expires"]) + + def test_modulo_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Modulo").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], ["creators", "contributors", "rights"] + ) diff --git a/src/design/plone/contenttypes/tests/test_ct_news.py b/src/design/plone/contenttypes/tests/test_ct_news.py index 764b3212..4239d9c2 100644 --- a/src/design/plone/contenttypes/tests/test_ct_news.py +++ b/src/design/plone/contenttypes/tests/test_ct_news.py @@ -1,12 +1,8 @@ # -*- coding: utf-8 -*- -from design.plone.contenttypes.controlpanels.settings import IDesignPloneSettings from design.plone.contenttypes.interfaces import IDesignPloneContentType from design.plone.contenttypes.testing import ( DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) -from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, -) from plone import api from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME @@ -20,13 +16,23 @@ import unittest -class TestNews(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestNewsSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING maxDiff = None def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() def test_behaviors_enabled_for_news(self): portal_types = api.portal.get_tool(name="portal_types") @@ -70,6 +76,134 @@ def test_news_provide_design_pct_marker_interface(self): news = api.content.create(container=self.portal, type="News Item", title="News") self.assertTrue(IDesignPloneContentType.providedBy(news)) + def test_news_item_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual(len(resp["fieldsets"]), 7) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "dates", + "correlati", + "categorization", + "settings", + "ownership", + "seo", + ], + ) + + def test_news_item_required_fields(self): + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + "descrizione_estesa", + "a_cura_di", + "tassonomia_argomenti", + "tipologia_notizia", + "description", + ] + ), + ) + + def test_news_item_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "image", + "image_caption", + "preview_image", + "preview_caption", + "descrizione_estesa", + "numero_progressivo_cs", + "a_cura_di", + "a_cura_di_persone", + "luoghi_correlati", + "tassonomia_argomenti", + "tipologia_notizia", + ], + ) + + def test_news_item_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual(resp["fieldsets"][1]["fields"], ["effective", "expires"]) + + def test_news_item_fields_correlati_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + ["notizie_correlate", "correlato_in_evidenza"], + ) + + def test_news_item_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], ["subjects", "language", "relatedItems"] + ) + + def test_news_item_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + [ + "allow_discussion", + "id", + "exclude_from_nav", + "versioning_enabled", + "changeNote", + ], + ) + + def test_news_item_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual( + resp["fieldsets"][5]["fields"], ["creators", "contributors", "rights"] + ) + + def test_news_item_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/News%20Item").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) + class TestNewsApi(unittest.TestCase): layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING @@ -89,12 +223,6 @@ def setUp(self): container=self.portal, type="Document", title="Document" ) - # we need it because of vocabularies - api.portal.set_registry_record( - "tipologie_notizia", - json.dumps({"en": ["foo", "bar"]}), - interface=IDesignPloneSettings, - ) transaction.commit() def tearDown(self): diff --git a/src/design/plone/contenttypes/tests/test_ct_pagina_argomento.py b/src/design/plone/contenttypes/tests/test_ct_pagina_argomento.py index e598271d..35ceb755 100644 --- a/src/design/plone/contenttypes/tests/test_ct_pagina_argomento.py +++ b/src/design/plone/contenttypes/tests/test_ct_pagina_argomento.py @@ -1,19 +1,34 @@ # -*- coding: utf-8 -*- """Setup tests for this package.""" from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, + 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 import unittest -class TestPaginaArgomento(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestPaginaArgomentoSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() def test_behaviors_enabled_for_pagina_argomento(self): portal_types = api.portal.get_tool(name="portal_types") @@ -39,3 +54,127 @@ def test_behaviors_enabled_for_pagina_argomento(self): "plone.versioning", ), ) + + def test_pagina_argomento_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual(len(resp["fieldsets"]), 8) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "informazioni", + # "correlati", questo non viene fuori nei test + "categorization", + "dates", + "settings", + "layout", + "ownership", + "seo", + ], + ) + + def test_pagina_argomento_required_fields(self): + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + ] + ), + ) + + def test_pagina_argomento_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "icona", + "unita_amministrative_responsabili", + "image", + "image_caption", + "preview_image", + "preview_caption", + ], + ) + + def test_pagina_argomento_fields_informazioni_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual(resp["fieldsets"][1]["fields"], ["ulteriori_informazioni"]) + + def test_pagina_argomento_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], ["relatedItems", "subjects", "language"] + ) + + def test_pagina_argomento_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual(resp["fieldsets"][3]["fields"], ["effective", "expires"]) + + def test_pagina_argomento_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "changeNote", + ], + ) + + def test_pagina_argomento_fields_layout_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual(resp["fieldsets"][5]["fields"], ["blocks", "blocks_layout"]) + + def test_pagina_argomento_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], ["creators", "contributors", "rights"] + ) + + def test_pagina_argomento_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Pagina%20Argomento").json() + self.assertEqual( + resp["fieldsets"][7]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) diff --git a/src/design/plone/contenttypes/tests/test_ct_persona.py b/src/design/plone/contenttypes/tests/test_ct_persona.py index 7a8c7ba6..a61598c3 100644 --- a/src/design/plone/contenttypes/tests/test_ct_persona.py +++ b/src/design/plone/contenttypes/tests/test_ct_persona.py @@ -3,10 +3,8 @@ from design.plone.contenttypes.testing import ( DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) -from design.plone.contenttypes.testing import ( - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, -) from plone import api +from plone.app.testing import helpers from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME from plone.app.testing import SITE_OWNER_PASSWORD @@ -22,12 +20,29 @@ import unittest -class TestPersona(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestPersonaSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + self.persona = api.content.create( + container=self.portal, type="Persona", title="John Doe" + ) + intids = getUtility(IIntIds) + + self.persona_ref = RelationValue(intids.getId(self.persona)) + commit() + + def tearDown(self): + self.api_session.close() def test_behaviors_enabled_for_persona(self): portal_types = api.portal.get_tool(name="portal_types") @@ -57,33 +72,143 @@ def test_persona_ct_title(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual("Persona pubblica", portal_types["Persona"].title) + def test_persona_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual(len(resp["fieldsets"]), 10) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "ruolo", + "contatti", + "documenti", + "informazioni", + # "correlati", questo non viene fuori nei test + "categorization", + "dates", + "ownership", + "settings", + "seo", + ], + ) -class TestPersonaEndpoint(unittest.TestCase): - """""" + def test_persona_required_fields(self): + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + "contact_info", + ] + ), + ) - layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING + def test_persona_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + ["title", "description", "foto_persona"], + ) - 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() - setRoles(self.portal, TEST_USER_ID, ["Manager"]) + def test_persona_fields_ruolo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + ["incarichi_persona", "competenze", "deleghe", "biografia"], + ) - 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) + def test_persona_fields_contatti_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual(resp["fieldsets"][2]["fields"], ["contact_info"]) - self.persona = api.content.create( - container=self.portal, type="Persona", title="John Doe" + def test_persona_fields_documenti_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual(resp["fieldsets"][3]["fields"], ["curriculum_vitae"]) + + def test_persona_fields_informazioni_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + ["ulteriori_informazioni"], ) - intids = getUtility(IIntIds) - self.persona_ref = RelationValue(intids.getId(self.persona)) - commit() + def test_persona_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + resp["fieldsets"][5]["fields"], ["relatedItems", "subjects", "language"] + ) - def tearDown(self): - self.api_session.close() + def test_persona_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual(resp["fieldsets"][6]["fields"], ["effective", "expires"]) + + def test_persona_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + resp["fieldsets"][7]["fields"], ["creators", "contributors", "rights"] + ) + + def test_persona_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + resp["fieldsets"][8]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "changeNote", + ], + ) + + def test_persona_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Persona").json() + self.assertEqual( + resp["fieldsets"][9]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) def test_atto_di_nomina_incarico(self): incarico = api.content.create( @@ -130,3 +255,28 @@ def test_delete_incarico_and_call_persona(self): )() # non ho incarichi, ma soprattutto non ho errori self.assertTrue(len(summary["incarichi"]) == 0) + + @unittest.skip + def test_unauthorized_on_subfolder(self): + incarico = api.content.create( + container=self.persona.incarichi, type="Incarico", title="Sindaco" + ) + commit() + intids = getUtility(IIntIds) + self.persona.incarichi_persona = [RelationValue(intids.getId(incarico))] + api.content.transition(obj=self.persona, transition="publish") + commit() + + helpers.logout() + # with previous bug this as anonymous user return + # AccessControl.unauthorized.Unauthorized: You are not allowed to + # access '_Access_inactive_portal_content_Permission' in this context + persona_summary = getMultiAdapter( + (self.persona, self.request), ISerializeToJsonSummary + )() + self.assertEqual(persona_summary["incarichi"], "Sindaco") + incarico_summary = getMultiAdapter( + (self.persona.incarichi.sindaco, self.request), ISerializeToJsonSummary + )() + self.assertEqual(incarico_summary["compensi_file"], []) + self.assertEqual(incarico_summary["importi_di_viaggio_e_o_servizi"], []) diff --git a/src/design/plone/contenttypes/tests/test_ct_servizio.py b/src/design/plone/contenttypes/tests/test_ct_servizio.py index 0b8935fc..bd7f21df 100644 --- a/src/design/plone/contenttypes/tests/test_ct_servizio.py +++ b/src/design/plone/contenttypes/tests/test_ct_servizio.py @@ -1,11 +1,8 @@ # -*- coding: utf-8 -*- """Setup tests for this package.""" -from design.plone.contenttypes.testing import ( # noqa +from design.plone.contenttypes.testing import ( DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING, ) -from design.plone.contenttypes.testing import ( # noqa - DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING, -) from plone import api from plone.app.testing import setRoles from plone.app.testing import SITE_OWNER_NAME @@ -44,15 +41,24 @@ } -class TestServizio(unittest.TestCase): - layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING +class TestServizioSchema(unittest.TestCase): + layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING maxDiff = None def setUp(self): - """Custom shared utility setup for tests.""" + self.app = self.layer["app"] self.portal = self.layer["portal"] + self.request = self.layer["request"] + self.portal_url = self.portal.absolute_url() setRoles(self.portal, TEST_USER_ID, ["Manager"]) + 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) + + def tearDown(self): + self.api_session.close() + def test_behaviors_enabled_for_servizio(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual( @@ -83,6 +89,259 @@ def test_behaviors_enabled_for_servizio(self): ), ) + def test_servizio_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual(len(resp["fieldsets"]), 18) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "cose", + "a_chi_si_rivolge", + "accedi_al_servizio", + "cosa_serve", + "costi_e_vincoli", + "tempi_e_scadenze", + "casi_particolari", + "contatti", + "documenti", + "link_utili", + "informazioni", + "correlati", + "categorization", + "settings", + "ownership", + "dates", + "seo", + ], + ) + + def test_servizio_required_fields(self): + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + "tassonomia_argomenti", + "a_chi_si_rivolge", + "come_si_fa", + "cosa_si_ottiene", + "cosa_serve", + "tempi_e_scadenze", + "ufficio_responsabile", + "contact_info", + "description", + ] + ), + ) + + def test_servizio_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "sottotitolo", + "stato_servizio", + "motivo_stato_servizio", + "condizioni_di_servizio", + "image", + "image_caption", + "preview_image", + "preview_caption", + "correlato_in_evidenza", + "tassonomia_argomenti", + "person_life_events", + "business_events", + ], + ) + + def test_servizio_fields_cose_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][1]["fields"], + ["descrizione_estesa"], + ) + + def test_servizio_fields_a_chi_si_rivolge_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + ["a_chi_si_rivolge", "chi_puo_presentare", "copertura_geografica"], + ) + + def test_servizio_fields_accedi_al_servizio_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], + [ + "come_si_fa", + "cosa_si_ottiene", + "procedure_collegate", + "canale_digitale", + "canale_digitale_link", + "canale_fisico", + "dove_rivolgersi", + "dove_rivolgersi_extra", + "prenota_appuntamento", + ], + ) + + def test_servizio_fields_cosa_serve_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + ["cosa_serve"], + ) + + def test_servizio_fields_costi_e_vincoli_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual(resp["fieldsets"][5]["fields"], ["costi", "vincoli"]) + + def test_servizio_fields_tempi_e_scadenze_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], + ["tempi_e_scadenze", "timeline_tempi_scadenze"], + ) + + def test_servizio_fields_casi_particolari_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual(resp["fieldsets"][7]["fields"], ["casi_particolari"]) + + def test_servizio_fields_contatti_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][8]["fields"], + ["ufficio_responsabile", "area", "contact_info"], + ) + + def test_servizio_fields_documenti_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual(resp["fieldsets"][9]["fields"], ["altri_documenti"]) + + def test_servizio_fields_link_utili_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual(resp["fieldsets"][10]["fields"], ["link_siti_esterni"]) + + def test_servizio_fields_informazioni_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][11]["fields"], + ["codice_ipa", "settore_merceologico", "ulteriori_informazioni"], + ) + + def test_servizio_fields_correlati_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][12]["fields"], + ["servizi_collegati"], + ) + + def test_servizio_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][13]["fields"], + ["identificativo", "subjects", "language", "relatedItems"], + ) + + def test_servizio_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][14]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "changeNote", + ], + ) + + def test_servizio_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][15]["fields"], ["creators", "contributors", "rights"] + ) + + def test_servizio_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual(resp["fieldsets"][16]["fields"], ["effective", "expires"]) + + def test_servizio_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/Servizio").json() + self.assertEqual( + resp["fieldsets"][17]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) + class TestServizioApi(unittest.TestCase): """Test that design.plone.contenttypes is properly installed.""" diff --git a/src/design/plone/contenttypes/tests/test_ct_unita_organizzativa.py b/src/design/plone/contenttypes/tests/test_ct_unita_organizzativa.py index ab1292e6..9e05347f 100644 --- a/src/design/plone/contenttypes/tests/test_ct_unita_organizzativa.py +++ b/src/design/plone/contenttypes/tests/test_ct_unita_organizzativa.py @@ -21,6 +21,239 @@ import unittest +class TestUOSchema(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() + setRoles(self.portal, TEST_USER_ID, ["Manager"]) + + 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) + + def tearDown(self): + self.api_session.close() + + def test_behaviors_enabled_for_uo(self): + portal_types = api.portal.get_tool(name="portal_types") + self.assertEqual( + portal_types["UnitaOrganizzativa"].behaviors, + ( + "plone.namefromtitle", + "plone.allowdiscussion", + "plone.excludefromnavigation", + "plone.shortname", + "plone.ownership", + "plone.publication", + "plone.categorization", + "plone.basic", + "plone.locking", + "plone.leadimage", + "volto.preview_image", + "plone.relateditems", + "design.plone.contenttypes.behavior.contatti_uo", + "design.plone.contenttypes.behavior.argomenti", + "plone.textindexer", + "design.plone.contenttypes.behavior.additional_help_infos", + "plone.translatable", + "kitconcept.seo", + "plone.versioning", + "collective.taxonomy.generated.tipologia_organizzazione", + ), + ) + + def test_uo_ct_title(self): + portal_types = api.portal.get_tool(name="portal_types") + self.assertEqual( + "Unita Organizzativa", portal_types["UnitaOrganizzativa"].title + ) + + def test_uo_fieldsets(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual(len(resp["fieldsets"]), 12) + self.assertEqual( + [x.get("id") for x in resp["fieldsets"]], + [ + "default", + "cosa_fa", + "struttura", + "persone", + "contatti", + "correlati", + "categorization", + "informazioni", + "settings", + "ownership", + "dates", + "seo", + ], + ) + + def test_uo_required_fields(self): + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + sorted(resp["required"]), + sorted( + [ + "title", + "competenze", + "tipologia_organizzazione", + "sede", + "contact_info", + "description", + ] + ), + ) + + def test_uo_fields_default_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][0]["fields"], + [ + "title", + "description", + "image", + "image_caption", + "preview_image", + "preview_caption", + "tassonomia_argomenti", + ], + ) + + def test_uo_fields_cosa_fa_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual(resp["fieldsets"][1]["fields"], ["competenze"]) + + def test_uo_fields_struttura_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][2]["fields"], + [ + "legami_con_altre_strutture", + "responsabile", + "assessore_riferimento", + "tipologia_organizzazione", + ], + ) + + def test_uo_fields_persone_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][3]["fields"], + ["persone_struttura"], + ) + + def test_uo_fields_contatti_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][4]["fields"], + ["contact_info", "sede", "sedi_secondarie", "orario_pubblico"], + ) + + def test_uo_fields_correlati_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][5]["fields"], + # ["documenti_pubblici", "correlato_in_evidenza"], # BBB dovrebbe essere così + # ma viene fuori così nei test perché non viene vista la patch SchemaTweaks + ["correlato_in_evidenza"], + ) + + def test_uo_fields_categorization_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][6]["fields"], + # ["subjects", "language"] BBB dovrebbe essere così + # ma nei test esce così perché non viene vista la patch di SchemaTweaks + ["subjects", "language", "relatedItems", "documenti_pubblici"], + ) + + def test_uo_fields_informazioni_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual(resp["fieldsets"][7]["fields"], ["ulteriori_informazioni"]) + + def test_uo_fields_settings_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][8]["fields"], + [ + "allow_discussion", + "exclude_from_nav", + "id", + "versioning_enabled", + "changeNote", + ], + ) + + def test_uo_fields_ownership_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][9]["fields"], ["creators", "contributors", "rights"] + ) + + def test_uo_fields_dates_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual(resp["fieldsets"][10]["fields"], ["effective", "expires"]) + + def test_uo_fields_seo_fieldset(self): + """ + Get the list from restapi + """ + resp = self.api_session.get("@types/UnitaOrganizzativa").json() + self.assertEqual( + resp["fieldsets"][11]["fields"], + [ + "seo_title", + "seo_description", + "seo_noindex", + "seo_canonical_url", + "opengraph_title", + "opengraph_description", + "opengraph_image", + ], + ) + + class TestUO(unittest.TestCase): """Test that design.plone.contenttypes is properly installed.""" @@ -91,42 +324,6 @@ def setUp(self): def tearDown(self): self.api_session.close() - def test_behaviors_enabled_for_uo(self): - portal_types = api.portal.get_tool(name="portal_types") - self.assertEqual( - portal_types["UnitaOrganizzativa"].behaviors, - ( - "plone.namefromtitle", - "plone.allowdiscussion", - "plone.excludefromnavigation", - "plone.shortname", - "plone.ownership", - "plone.publication", - "plone.categorization", - "plone.basic", - "plone.locking", - "plone.leadimage", - "volto.preview_image", - "plone.relateditems", - # "design.plone.contenttypes.behavior.address_uo", - # "design.plone.contenttypes.behavior.geolocation_uo", - "design.plone.contenttypes.behavior.contatti_uo", - "design.plone.contenttypes.behavior.argomenti", - "plone.textindexer", - "design.plone.contenttypes.behavior.additional_help_infos", - "plone.translatable", - "kitconcept.seo", - "plone.versioning", - "collective.taxonomy.generated.tipologia_organizzazione", - ), - ) - - def test_uo_ct_title(self): - portal_types = api.portal.get_tool(name="portal_types") - self.assertEqual( - "Unita Organizzativa", portal_types["UnitaOrganizzativa"].title - ) - def test_uo_service_related_service_show_only_services(self): response = self.api_session.get(self.uo.absolute_url() + "?fullobjects") self.assertEqual( From 3ad0dae2000b3cf78abbda057a03678360f86cde Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 16 Oct 2023 15:08:29 +0200 Subject: [PATCH 02/23] make package more extensible --- .../contenttypes/behaviors/configure.zcml | 8 -- .../plone/contenttypes/events/evento.py | 15 +- .../plone/contenttypes/events/persona.py | 53 +++---- .../restapi/serializers/dxcontent.py | 59 +++----- .../contenttypes/vocabularies/configure.zcml | 5 - .../vocabularies/reference_vocabularies.py | 2 +- .../vocabularies/tags_vocabulary.py | 131 +++++++++--------- 7 files changed, 127 insertions(+), 146 deletions(-) diff --git a/src/design/plone/contenttypes/behaviors/configure.zcml b/src/design/plone/contenttypes/behaviors/configure.zcml index 204c1e03..7f9ab72f 100644 --- a/src/design/plone/contenttypes/behaviors/configure.zcml +++ b/src/design/plone/contenttypes/behaviors/configure.zcml @@ -251,14 +251,6 @@ provides=".contatti.IContattiEvent" marker=".contatti.IContattiEvent" /> - - - diff --git a/src/design/plone/contenttypes/vocabularies/reference_vocabularies.py b/src/design/plone/contenttypes/vocabularies/reference_vocabularies.py index cc46d8ba..bfa2ef40 100644 --- a/src/design/plone/contenttypes/vocabularies/reference_vocabularies.py +++ b/src/design/plone/contenttypes/vocabularies/reference_vocabularies.py @@ -12,7 +12,7 @@ from zope.schema.interfaces import IVocabularyFactory from zope.schema.vocabulary import SimpleTerm from zope.schema.vocabulary import SimpleVocabulary -from zope.site.hooks import getSite +from zope.component.hooks import getSite class ReferencesVocabulary(object): diff --git a/src/design/plone/contenttypes/vocabularies/tags_vocabulary.py b/src/design/plone/contenttypes/vocabularies/tags_vocabulary.py index 4df59b1a..23f71883 100644 --- a/src/design/plone/contenttypes/vocabularies/tags_vocabulary.py +++ b/src/design/plone/contenttypes/vocabularies/tags_vocabulary.py @@ -14,6 +14,72 @@ def __init__(self, token, value): self.value = value +TAGS_MAPPING = [ + ("accesso_all_informazione", _("Accesso all'informazione")), + ("acqua", _("Acqua")), + ("agricoltura", _("Agricoltura")), + ("animale_domestico", _("Animale domestico")), + ("aria", _("Aria")), + ("assistenza_agli_anziani", _("Assistenza agli invalidi")), + ("assistenza_sociale", _("Assistenza sociale")), + ("associazioni", _("Associazioni")), + ("bilancio", _("Bilancio")), + ("commercio_all_ingresso", _("Commercio all'ingrosso")), + ("commercio_al_minuto", _("Commercio al minuto")), + ("commercio_ambulante", _("Commercio ambulante")), + ("comunicazione_istituzionale", _("Comunicazione istituzionale")), + ("comunicazione_politica", _("Comunicazione politica")), + ("concordi", _("Concorsi")), + ("covid_19", _("Covid - 19")), + ("elezioni", _("Elezioni")), + ("energie_rinnovabili", _("Energie rinnovabili")), + ("estero", _("Estero")), + ("foreste", _("Foreste")), + ("formazione_professionale", _("Formazione professionale")), + ("gemellaggi", _("Gemellaggi")), + ("gestione_rifiuti", _("Gestione rifiuti")), + ("giustizia", _("Giustizia")), + ("igiene_pubblica", _("Igiene pubblica")), + ("immigrazione", _("Immigrazione")), + ("imposte", _("Imposte")), + ("imprese", _("Imprese")), + ("inquinamento", _("Inquinamento")), + ("integrazione_sociale", _("Integrazione sociale")), + ("isolamento_termico", _("Isolamento termico")), + ("istruzione", _("Istruzione")), + ("lavoro", _("Lavoro")), + ("matrimonio", _("Matrimonio")), + ("mercato", _("Mercato")), + ("mobilita_sostenibile", _("Mobilità sostenibile")), + ("morte", _("Morte")), + ("nascita", _("Nascita")), + ("parcheggi", _("Parcheggi")), + ("patrimonio_culturale", _("Patrimonio culturale")), + ("pesca", _("Pesca")), + ("piano_di_sviluppo", _("Piano di sviluppo")), + ("pista_ciclabile", _("Pista ciclabile")), + ("politica_commerciale", _("Politica commerciale")), + ("polizia", _("Polizia")), + ("prodotti_alimentari", _("Prodotti alimentari")), + ("protezione_civile", _("Protezione civile")), + ("residenza", _("Residenza")), + ("risposta_alle_emergenze", _("Risposta alle emergenze")), + ("sistema_giuridico", _("Sistema giuridico")), + ("spazio_verde", _("Spazio Verde")), + ("sport", _("Sport")), + ("sviluppo_sostenibile", _("Sviluppo sostenibile")), + ("tassa_sui_servizi", _("Tassa sui servizi")), + ("tempo_libero", _("Tempo libero")), + ("trasparenza_amministrativa", _("Trasparenza amministrativa")), + ("trasporto_pubblico", _("Trasporto pubblico")), + ("turismo", _("Turismo")), + ("urbanizzazione", _("Urbanizzazione")), + ("viaggi", _("Viaggi")), + ("zone_pedonali", _("Zone pedonali")), + ("ztl", _("ZTL")), +] + + @implementer(IVocabularyFactory) class TagsVocabulary(object): """ """ @@ -21,70 +87,7 @@ class TagsVocabulary(object): def __call__(self, context): # Just an example list of content for our vocabulary, # this can be any static or dynamic data, a catalog result for example. - items = [ - VocabItem("accesso_all_informazione", _("Accesso all'informazione")), - VocabItem("acqua", _("Acqua")), - VocabItem("agricoltura", _("Agricoltura")), - VocabItem("animale_domestico", _("Animale domestico")), - VocabItem("aria", _("Aria")), - VocabItem("assistenza_agli_anziani", _("Assistenza agli invalidi")), - VocabItem("assistenza_sociale", _("Assistenza sociale")), - VocabItem("associazioni", _("Associazioni")), - VocabItem("bilancio", _("Bilancio")), - VocabItem("commercio_all_ingresso", _("Commercio all'ingrosso")), - VocabItem("commercio_al_minuto", _("Commercio al minuto")), - VocabItem("commercio_ambulante", _("Commercio ambulante")), - VocabItem("comunicazione_istituzionale", _("Comunicazione istituzionale")), - VocabItem("comunicazione_politica", _("Comunicazione politica")), - VocabItem("concordi", _("Concorsi")), - VocabItem("covid_19", _("Covid - 19")), - VocabItem("elezioni", _("Elezioni")), - VocabItem("energie_rinnovabili", _("Energie rinnovabili")), - VocabItem("estero", _("Estero")), - VocabItem("foreste", _("Foreste")), - VocabItem("formazione_professionale", _("Formazione professionale")), - VocabItem("gemellaggi", _("Gemellaggi")), - VocabItem("gestione_rifiuti", _("Gestione rifiuti")), - VocabItem("giustizia", _("Giustizia")), - VocabItem("igiene_pubblica", _("Igiene pubblica")), - VocabItem("immigrazione", _("Immigrazione")), - VocabItem("imposte", _("Imposte")), - VocabItem("imprese", _("Imprese")), - VocabItem("inquinamento", _("Inquinamento")), - VocabItem("integrazione_sociale", _("Integrazione sociale")), - VocabItem("isolamento_termico", _("Isolamento termico")), - VocabItem("istruzione", _("Istruzione")), - VocabItem("lavoro", _("Lavoro")), - VocabItem("matrimonio", _("Matrimonio")), - VocabItem("mercato", _("Mercato")), - VocabItem("mobilita_sostenibile", _("Mobilità sostenibile")), - VocabItem("morte", _("Morte")), - VocabItem("nascita", _("Nascita")), - VocabItem("parcheggi", _("Parcheggi")), - VocabItem("patrimonio_culturale", _("Patrimonio culturale")), - VocabItem("pesca", _("Pesca")), - VocabItem("piano_di_sviluppo", _("Piano di sviluppo")), - VocabItem("pista_ciclabile", _("Pista ciclabile")), - VocabItem("politica_commerciale", _("Politica commerciale")), - VocabItem("polizia", _("Polizia")), - VocabItem("prodotti_alimentari", _("Prodotti alimentari")), - VocabItem("protezione_civile", _("Protezione civile")), - VocabItem("residenza", _("Residenza")), - VocabItem("risposta_alle_emergenze", _("Risposta alle emergenze")), - VocabItem("sistema_giuridico", _("Sistema giuridico")), - VocabItem("spazio_verde", _("Spazio Verde")), - VocabItem("sport", _("Sport")), - VocabItem("sviluppo_sostenibile", _("Sviluppo sostenibile")), - VocabItem("tassa_sui_servizi", _("Tassa sui servizi")), - VocabItem("tempo_libero", _("Tempo libero")), - VocabItem("trasparenza_amministrativa", _("Trasparenza amministrativa")), - VocabItem("trasporto_pubblico", _("Trasporto pubblico")), - VocabItem("turismo", _("Turismo")), - VocabItem("urbanizzazione", _("Urbanizzazione")), - VocabItem("viaggi", _("Viaggi")), - VocabItem("zone_pedonali", _("Zone pedonali")), - VocabItem("ztl", _("ZTL")), - ] + items = [VocabItem(token=token, value=value) for token, value in TAGS_MAPPING] # Fix context if you are using the vocabulary in DataGridField. # See https://github.com/collective/collective.z3cform.datagridfield/issues/31: # NOQA: 501 From 27ab421aaffb62146bf621f7abe3cdd4075b1aae Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Tue, 24 Oct 2023 11:05:05 +0200 Subject: [PATCH 03/23] Do not show fieldsets with no visible fields in @types endpoint. --- CHANGES.rst | 3 ++- .../restapi/services/types/get.py | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 71ffdd68..5ec6bde0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,8 @@ Changelog 6.0.17 (unreleased) ------------------- -- Nothing changed yet. +- Do not show fieldsets with no visible fields in @types endpoint. + [cekk] 6.0.16 (2023-08-24) diff --git a/src/design/plone/contenttypes/restapi/services/types/get.py b/src/design/plone/contenttypes/restapi/services/types/get.py index f74dc8a0..c68697d4 100644 --- a/src/design/plone/contenttypes/restapi/services/types/get.py +++ b/src/design/plone/contenttypes/restapi/services/types/get.py @@ -276,9 +276,8 @@ def customize_documento_schema(self, result): def reply(self): result = super(TypesGet, self).reply() - if "fieldsets" in result: - result["fieldsets"] = self.reorder_fieldsets(original=result["fieldsets"]) + result["fieldsets"] = self.reorder_fieldsets(schema=result) pt = self.request.PATH_INFO.split("/")[-1] # be careful: result could be dict or list. If list it will not @@ -308,7 +307,8 @@ def reply(self): def get_order_by_type(self, portal_type): return [x for x in FIELDSETS_ORDER.get(portal_type, [])] - def reorder_fieldsets(self, original): + def reorder_fieldsets(self, schema): + original = schema["fieldsets"] pt = self.request.PATH_INFO.split("/")[-1] order = self.get_order_by_type(portal_type=pt) if not order: @@ -326,9 +326,21 @@ def reorder_fieldsets(self, original): new = [] for id in order: for fieldset in original: - if fieldset["id"] == id: + if fieldset["id"] == id and self.fieldset_has_fields(fieldset, schema): new.append(fieldset) if not new: # no match return original return new + + def fieldset_has_fields(self, fieldset, schema): + """ + If a fieldset has all hidden fields (maybe after a schema tweak), + these are not in the schema data, but are still in fieldset data. + This happens only in add, because the schema is generate with the parent's context. + """ + fieldset_fields = fieldset["fields"] + + schema_fields = [x for x in fieldset_fields if x in schema["properties"].keys()] + + return len(schema_fields) > 0 From 6eb94bc897a34d216a6659ad35943a1489bc35b2 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 25 Oct 2023 16:07:19 +0200 Subject: [PATCH 04/23] lower log level --- src/design/plone/contenttypes/restapi/serializers/summary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/design/plone/contenttypes/restapi/serializers/summary.py b/src/design/plone/contenttypes/restapi/serializers/summary.py index 8ad94fd6..e1e819ae 100644 --- a/src/design/plone/contenttypes/restapi/serializers/summary.py +++ b/src/design/plone/contenttypes/restapi/serializers/summary.py @@ -193,7 +193,7 @@ def get_design_meta_type(self): ttool[self.context.portal_type].Title(), context=self.request ) else: - logger.error( + logger.warning( "missing portal_type %s for %s", self.context.portal_type, self.context.absolute_url(), From 43e74fa4a155ee8dd51085283bac72e9f91aec2e Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Tue, 7 Nov 2023 15:30:57 +0100 Subject: [PATCH 05/23] fix test --- src/design/plone/contenttypes/tests/test_ct_persona.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/design/plone/contenttypes/tests/test_ct_persona.py b/src/design/plone/contenttypes/tests/test_ct_persona.py index 2e59708c..fdaea25f 100644 --- a/src/design/plone/contenttypes/tests/test_ct_persona.py +++ b/src/design/plone/contenttypes/tests/test_ct_persona.py @@ -273,7 +273,7 @@ def test_unauthorized_on_subfolder(self): persona_summary = getMultiAdapter( (self.persona, self.request), ISerializeToJsonSummary )() - self.assertEqual(persona_summary["incarichi"], "Sindaco") + self.assertFalse(persona_summary["incarichi"]) incarico_summary = getMultiAdapter( (self.persona.incarichi.sindaco, self.request), ISerializeToJsonSummary )() From d5abe9833d7bbccae6649a48b7180e26cbe0b07d Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Thu, 25 Jan 2024 16:30:24 +0100 Subject: [PATCH 06/23] Add getObjSize info in File field serializer --- CHANGES.rst | 3 ++- .../contenttypes/restapi/serializers/dxfields.py | 11 +++++++++-- .../tests/test_filefield_view_mode_serializer.py | 5 ++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 27756c9d..4306f573 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,8 @@ Changelog 6.1.11 (unreleased) ------------------- -- Nothing changed yet. +- Add getObjSize info in File field serializer. + [cekk] 6.1.10 (2024-01-16) diff --git a/src/design/plone/contenttypes/restapi/serializers/dxfields.py b/src/design/plone/contenttypes/restapi/serializers/dxfields.py index 1cf1ab10..133351c6 100644 --- a/src/design/plone/contenttypes/restapi/serializers/dxfields.py +++ b/src/design/plone/contenttypes/restapi/serializers/dxfields.py @@ -5,6 +5,7 @@ from design.plone.contenttypes.interfaces.servizio import IServizio from plone import api from plone.app.contenttypes.utils import replace_link_variables_by_paths +from plone.base.utils import human_readable_size from plone.dexterity.interfaces import IDexterityContent from plone.namedfile.interfaces import INamedFileField from plone.outputfilters.browser.resolveuid import uuidToURL @@ -56,7 +57,11 @@ def __call__(self): @adapter(INamedFileField, IDexterityContent, IDesignPloneContenttypesLayer) class FileFieldViewModeSerializer(DefaultFieldSerializer): - """Ovveride the basic DX serializer to handle the visualize file functionality""" + """ + Ovveride the basic DX serializer to: + - handle the visualize file functionality + - add getObjSize info + """ def __call__(self): namedfile = self.field.get(self.context) @@ -70,10 +75,12 @@ def __call__(self): self.field.__name__, ) ) + size = namedfile.getSize() result = { "filename": namedfile.filename, "content-type": namedfile.contentType, - "size": namedfile.getSize(), + "size": size, + "getObjSize": human_readable_size(size), "download": url, } diff --git a/src/design/plone/contenttypes/tests/test_filefield_view_mode_serializer.py b/src/design/plone/contenttypes/tests/test_filefield_view_mode_serializer.py index c0fb9737..b1532b2d 100644 --- a/src/design/plone/contenttypes/tests/test_filefield_view_mode_serializer.py +++ b/src/design/plone/contenttypes/tests/test_filefield_view_mode_serializer.py @@ -59,5 +59,8 @@ def test_if_visualize_files_true_so_dsiplay(self): commit() response = self.api_session.get(self.modulo.absolute_url()).json() - self.assertIn("@@display-file", response["file_principale"]["download"]) + + def test_human_readable_obj_size_in_data(self): + response = self.api_session.get(self.modulo.absolute_url()).json() + self.assertEqual("1 KB", response["file_principale"]["getObjSize"]) From f14babd8eff38c6f99d8919aa652648c02b815a3 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Fri, 26 Jan 2024 12:11:01 +0100 Subject: [PATCH 07/23] add collective.volto.enhancedlinks dependency (needed for slate integration) --- CHANGES.rst | 4 +++- base.cfg | 3 ++- setup.py | 1 + .../profiles/default/metadata.xml | 3 ++- .../profiles/default/types/Modulo.xml | 1 + .../restapi/serializers/dxfields.py | 16 ++++++++++++++- src/design/plone/contenttypes/testing.py | 3 +++ .../contenttypes/tests/test_ct_modulo.py | 5 +++-- ...py => test_filefield_custom_serializer.py} | 9 +++++++-- .../contenttypes/upgrades/configure.zcml | 10 ++++++++++ .../plone/contenttypes/upgrades/upgrades.py | 20 +++++++++++++++++++ 11 files changed, 67 insertions(+), 8 deletions(-) rename src/design/plone/contenttypes/tests/{test_filefield_view_mode_serializer.py => test_filefield_custom_serializer.py} (83%) diff --git a/CHANGES.rst b/CHANGES.rst index 4306f573..155fb5f8 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,9 @@ Changelog 6.1.11 (unreleased) ------------------- -- Add getObjSize info in File field serializer. +- Add collective.volto.enhancedlinks dependency (needed for slate integration). + [cekk] +- Add enhancedlinks infos in File field serializer. [cekk] diff --git a/base.cfg b/base.cfg index 7aaa4b1b..cd203669 100644 --- a/base.cfg +++ b/base.cfg @@ -33,7 +33,7 @@ environment-vars = eggs = Plone Pillow - design.plone.contenttypes [test] + design.plone.contenttypes [test,enhancedlinks] zcml-additional = - 7021 + 7030 profile-redturtle.bandi:default profile-collective.venue:default @@ -8,5 +8,6 @@ profile-eea.api.taxonomy:default profile-collective.z3cform.datagridfield:default profile-design.plone.contenttypes:taxonomy + profile-collective.volto.enhancedlinks:default diff --git a/src/design/plone/contenttypes/profiles/default/types/Modulo.xml b/src/design/plone/contenttypes/profiles/default/types/Modulo.xml index fe0ea9c1..1978e988 100644 --- a/src/design/plone/contenttypes/profiles/default/types/Modulo.xml +++ b/src/design/plone/contenttypes/profiles/default/types/Modulo.xml @@ -43,6 +43,7 @@ + diff --git a/src/design/plone/contenttypes/restapi/serializers/dxfields.py b/src/design/plone/contenttypes/restapi/serializers/dxfields.py index 133351c6..a03927c5 100644 --- a/src/design/plone/contenttypes/restapi/serializers/dxfields.py +++ b/src/design/plone/contenttypes/restapi/serializers/dxfields.py @@ -23,6 +23,13 @@ from zope.schema.interfaces import ISourceText from zope.schema.interfaces import ITextLine +try: + from collective.volto.enhancedlinks.interfaces import IEnhancedLinksEnabled + + HAS_ENHANCEDLINKS = True +except ImportError: + HAS_ENHANCEDLINKS = False + import json import re @@ -80,9 +87,16 @@ def __call__(self): "filename": namedfile.filename, "content-type": namedfile.contentType, "size": size, - "getObjSize": human_readable_size(size), "download": url, } + if HAS_ENHANCEDLINKS: + if IEnhancedLinksEnabled.providedBy(self.context): + result.update( + { + "getObjSize": human_readable_size(size), + "enhanced_links_enabled": True, + } + ) return json_compatible(result) diff --git a/src/design/plone/contenttypes/testing.py b/src/design/plone/contenttypes/testing.py index 035a1fec..f7284719 100644 --- a/src/design/plone/contenttypes/testing.py +++ b/src/design/plone/contenttypes/testing.py @@ -14,6 +14,7 @@ import collective.venue import collective.volto.blocksfield import collective.volto.cookieconsent +import collective.volto.enhancedlinks import collective.z3cform.datagridfield import design.plone.contenttypes import eea.api.taxonomy @@ -32,6 +33,7 @@ def setUpZope(self, app, configurationContext): super().setUpZope(app, configurationContext) self.loadZCML(package=collective.venue) self.loadZCML(package=collective.volto.blocksfield) + self.loadZCML(package=collective.volto.enhancedlinks) self.loadZCML(package=design.plone.contenttypes, context=configurationContext) self.loadZCML(package=plone.formwidget.geolocation) self.loadZCML(name="overrides.zcml", package=design.plone.contenttypes) @@ -71,6 +73,7 @@ def setUpZope(self, app, configurationContext): super().setUpZope(app, configurationContext) self.loadZCML(package=collective.venue) self.loadZCML(package=collective.volto.blocksfield) + self.loadZCML(package=collective.volto.enhancedlinks) self.loadZCML(package=design.plone.contenttypes, context=configurationContext) self.loadZCML(package=plone.formwidget.geolocation) self.loadZCML(package=eea.api.taxonomy) diff --git a/src/design/plone/contenttypes/tests/test_ct_modulo.py b/src/design/plone/contenttypes/tests/test_ct_modulo.py index e12bf364..e2bfdab0 100644 --- a/src/design/plone/contenttypes/tests/test_ct_modulo.py +++ b/src/design/plone/contenttypes/tests/test_ct_modulo.py @@ -8,14 +8,14 @@ import unittest -class TestDocument(unittest.TestCase): +class TestModulo(unittest.TestCase): layer = DESIGN_PLONE_CONTENTTYPES_INTEGRATION_TESTING def setUp(self): """Custom shared utility setup for tests.""" self.portal = self.layer["portal"] - def test_behaviors_enabled_for_documento(self): + def test_behaviors_enabled_for_modulo(self): portal_types = api.portal.get_tool(name="portal_types") self.assertEqual( portal_types["Modulo"].behaviors, @@ -29,5 +29,6 @@ def test_behaviors_enabled_for_documento(self): "plone.locking", "design.plone.contenttypes.behavior.multi_file", "plone.translatable", + "volto.enhanced_links_enabled", ), ) diff --git a/src/design/plone/contenttypes/tests/test_filefield_view_mode_serializer.py b/src/design/plone/contenttypes/tests/test_filefield_custom_serializer.py similarity index 83% rename from src/design/plone/contenttypes/tests/test_filefield_view_mode_serializer.py rename to src/design/plone/contenttypes/tests/test_filefield_custom_serializer.py index b1532b2d..2f478e86 100644 --- a/src/design/plone/contenttypes/tests/test_filefield_view_mode_serializer.py +++ b/src/design/plone/contenttypes/tests/test_filefield_custom_serializer.py @@ -14,7 +14,7 @@ import unittest -class SummarySerializerTest(unittest.TestCase): +class FileFieldSerializerTest(unittest.TestCase): layer = DESIGN_PLONE_CONTENTTYPES_API_FUNCTIONAL_TESTING def setUp(self): @@ -61,6 +61,11 @@ def test_if_visualize_files_true_so_dsiplay(self): response = self.api_session.get(self.modulo.absolute_url()).json() self.assertIn("@@display-file", response["file_principale"]["download"]) - def test_human_readable_obj_size_in_data(self): + def test_if_enhancedlinks_behavior_active_has_human_readable_obj_size_in_data(self): response = self.api_session.get(self.modulo.absolute_url()).json() self.assertEqual("1 KB", response["file_principale"]["getObjSize"]) + + def test_if_enhancedlinks_behavior_active_has_flag_in_data(self): + response = self.api_session.get(self.modulo.absolute_url()).json() + self.assertIn("enhanced_links_enabled", response["file_principale"]) + self.assertTrue(response["file_principale"]["enhanced_links_enabled"]) diff --git a/src/design/plone/contenttypes/upgrades/configure.zcml b/src/design/plone/contenttypes/upgrades/configure.zcml index e8fc5e60..541555aa 100644 --- a/src/design/plone/contenttypes/upgrades/configure.zcml +++ b/src/design/plone/contenttypes/upgrades/configure.zcml @@ -804,4 +804,14 @@ handler=".upgrades.update_pdc_with_pdc_desc" /> + + + diff --git a/src/design/plone/contenttypes/upgrades/upgrades.py b/src/design/plone/contenttypes/upgrades/upgrades.py index 6019d520..1ccf0148 100644 --- a/src/design/plone/contenttypes/upgrades/upgrades.py +++ b/src/design/plone/contenttypes/upgrades/upgrades.py @@ -1573,3 +1573,23 @@ def update_pdc_with_pdc_desc(context): v["pdc_desc"] = None logger.info(f"Set pdc_desc for {pdc.absolute_url()}") logger.info("Ends of update") + + +def to_7030(context): + installOrReinstallProduct(api.portal.get(), "collective.volto.enhancedlinks") + # add behavior to modulo + portal_types = api.portal.get_tool(name="portal_types") + modulo_behaviors = [x for x in portal_types["Modulo"].behaviors] + if "volto.enhanced_links_enabled" not in modulo_behaviors: + modulo_behaviors.append("volto.enhanced_links_enabled") + portal_types["Modulo"].behaviors = tuple(modulo_behaviors) + + # update index/metadata + brains = api.content.find(portal_type=["File", "Image", "Modulo"]) + tot = len(brains) + i = 0 + for brain in brains: + i += 1 + if i % 100 == 0: + logger.info("Progress: {}/{}".format(i, tot)) + brain.getObject().reindexObject(idxs=["enhanced_links_enabled"]) From 08d5bac6335545e8cc19a8391a760516d52ea44a Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Fri, 26 Jan 2024 14:15:35 +0100 Subject: [PATCH 08/23] initial work --- .../plone/contenttypes/controlpanels/settings.py | 10 ++++++++++ 1 file changed, 10 insertions(+) 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): From fa4cf9f3861a732323fe35236c07e6442ab1593c Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Fri, 26 Jan 2024 14:19:28 +0100 Subject: [PATCH 09/23] remove customizations --- CHANGES.rst | 6 ++---- base.cfg | 2 +- setup.py | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 512657fb..bcbe67be 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,15 +4,13 @@ Changelog 6.1.11 (unreleased) ------------------- +- Fixed script to update pdc with description + [eikichi18] - Add collective.volto.enhancedlinks dependency (needed for slate integration). [cekk] - Add enhancedlinks infos in File field serializer. -- Fixed script to update pdc with description - [eikichi18] -- Add getObjSize info in File field serializer. [cekk] - 6.1.10 (2024-01-16) ------------------- diff --git a/base.cfg b/base.cfg index cd203669..20b969de 100644 --- a/base.cfg +++ b/base.cfg @@ -33,7 +33,7 @@ environment-vars = eggs = Plone Pillow - design.plone.contenttypes [test,enhancedlinks] + design.plone.contenttypes [test] zcml-additional = Date: Sat, 27 Jan 2024 21:18:57 +0100 Subject: [PATCH 10/23] Add new flag in settings needed to choose to show or not auto-generated footer columns and Customize @navigation endpoint to expose also the new flag for frontend --- CHANGES.rst | 5 +- .../restapi/services/configure.zcml | 4 +- .../restapi/services/navigation/__init__.py | 0 .../services/navigation/configure.zcml | 22 +++++ .../restapi/services/navigation/get.py | 29 +++++++ .../tests/test_custom_service_navigation.py | 82 +++++++++++++++++++ .../contenttypes/upgrades/configure.zcml | 11 ++- 7 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 src/design/plone/contenttypes/restapi/services/navigation/__init__.py create mode 100644 src/design/plone/contenttypes/restapi/services/navigation/configure.zcml create mode 100644 src/design/plone/contenttypes/restapi/services/navigation/get.py create mode 100644 src/design/plone/contenttypes/tests/test_custom_service_navigation.py diff --git a/CHANGES.rst b/CHANGES.rst index e0b2077f..94faf86a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,7 +8,10 @@ Changelog [eikichi18] - Add getObjSize info 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/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..70e42e12 --- /dev/null +++ b/src/design/plone/contenttypes/restapi/services/navigation/get.py @@ -0,0 +1,29 @@ +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) + show_dynamic_folders_in_footer = api.portal.get_registry_record( + "show_dynamic_folders_in_footer", + interface=IDesignPloneSettings, + default=False, + ) + 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/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/upgrades/configure.zcml b/src/design/plone/contenttypes/upgrades/configure.zcml index 8e88bee8..c1896bd3 100644 --- a/src/design/plone/contenttypes/upgrades/configure.zcml +++ b/src/design/plone/contenttypes/upgrades/configure.zcml @@ -804,5 +804,14 @@ handler=".upgrades.update_pdc_with_pdc_desc" /> - + + + From 9a01432f7bb02529bdb7ef0f46f60c91c1ae975a Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Sat, 27 Jan 2024 21:19:11 +0100 Subject: [PATCH 11/23] zpretty --- .../contenttypes/restapi/services/navigation/configure.zcml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/design/plone/contenttypes/restapi/services/navigation/configure.zcml b/src/design/plone/contenttypes/restapi/services/navigation/configure.zcml index 66fff132..e9bc6b20 100644 --- a/src/design/plone/contenttypes/restapi/services/navigation/configure.zcml +++ b/src/design/plone/contenttypes/restapi/services/navigation/configure.zcml @@ -15,8 +15,8 @@ factory=".get.NavigationGet" for="zope.interface.Interface" permission="zope2.View" - name="@navigation" layer="design.plone.contenttypes.interfaces.IDesignPloneContenttypesLayer" + name="@navigation" /> From 9dd91ea6593d9168f0ee1103a1df8f5978be278f Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Sat, 27 Jan 2024 21:25:22 +0100 Subject: [PATCH 12/23] update readme --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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". From 9c3986935c27aa2636760e76519a1b7d1f542414 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 29 Jan 2024 16:37:13 +0100 Subject: [PATCH 13/23] add info also for image fields --- .../restapi/serializers/configure.zcml | 1 + .../restapi/serializers/dxfields.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/design/plone/contenttypes/restapi/serializers/configure.zcml b/src/design/plone/contenttypes/restapi/serializers/configure.zcml index d5c46918..e81c934a 100644 --- a/src/design/plone/contenttypes/restapi/serializers/configure.zcml +++ b/src/design/plone/contenttypes/restapi/serializers/configure.zcml @@ -22,6 +22,7 @@ + diff --git a/src/design/plone/contenttypes/restapi/serializers/dxfields.py b/src/design/plone/contenttypes/restapi/serializers/dxfields.py index a03927c5..8fe64a06 100644 --- a/src/design/plone/contenttypes/restapi/serializers/dxfields.py +++ b/src/design/plone/contenttypes/restapi/serializers/dxfields.py @@ -8,12 +8,16 @@ from plone.base.utils import human_readable_size from plone.dexterity.interfaces import IDexterityContent from plone.namedfile.interfaces import INamedFileField +from plone.namedfile.interfaces import INamedImageField from plone.outputfilters.browser.resolveuid import uuidToURL from plone.restapi.interfaces import IBlockFieldSerializationTransformer from plone.restapi.interfaces import IFieldSerializer from plone.restapi.interfaces import ISerializeToJsonSummary from plone.restapi.serializer.converters import json_compatible from plone.restapi.serializer.dxfields import DefaultFieldSerializer +from plone.restapi.serializer.dxfields import ( + ImageFieldSerializer as BaseImageFieldSerializer, +) from zope.component import adapter from zope.component import getMultiAdapter from zope.component import subscribers @@ -109,6 +113,21 @@ def get_file_view_mode(self, content_type): return "@@download" +@adapter(INamedImageField, IDexterityContent, IDesignPloneContenttypesLayer) +class ImageFieldSerializer(BaseImageFieldSerializer): + def __call__(self): + result = super().__call__() + if HAS_ENHANCEDLINKS: + if IEnhancedLinksEnabled.providedBy(self.context): + result.update( + { + "getObjSize": human_readable_size(result["size"]), + "enhanced_links_enabled": True, + } + ) + return result + + def serialize_data(context, json_data, show_children=False): request = getRequest() if not json_data: From 6d5fbffeb22dd5b19950b70a81b8f7153bcb5386 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Tue, 30 Jan 2024 14:47:01 +0100 Subject: [PATCH 14/23] fix imports --- .../contenttypes/adapters/configure.zcml | 1 + .../restapi/serializers/dxfields.py | 37 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/design/plone/contenttypes/adapters/configure.zcml b/src/design/plone/contenttypes/adapters/configure.zcml index 8f7a3224..7e7188fd 100644 --- a/src/design/plone/contenttypes/adapters/configure.zcml +++ b/src/design/plone/contenttypes/adapters/configure.zcml @@ -20,4 +20,5 @@ factory=".searchabletext_indexers.TextBlockSearchableText" name="text" /> + diff --git a/src/design/plone/contenttypes/restapi/serializers/dxfields.py b/src/design/plone/contenttypes/restapi/serializers/dxfields.py index 8fe64a06..ef0be61e 100644 --- a/src/design/plone/contenttypes/restapi/serializers/dxfields.py +++ b/src/design/plone/contenttypes/restapi/serializers/dxfields.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from AccessControl.unauthorized import Unauthorized from Acquisition import aq_inner +from collective.volto.enhancedlinks.interfaces import IEnhancedLinksEnabled from design.plone.contenttypes.interfaces import IDesignPloneContenttypesLayer from design.plone.contenttypes.interfaces.servizio import IServizio from plone import api @@ -27,12 +28,6 @@ from zope.schema.interfaces import ISourceText from zope.schema.interfaces import ITextLine -try: - from collective.volto.enhancedlinks.interfaces import IEnhancedLinksEnabled - - HAS_ENHANCEDLINKS = True -except ImportError: - HAS_ENHANCEDLINKS = False import json import re @@ -93,14 +88,13 @@ def __call__(self): "size": size, "download": url, } - if HAS_ENHANCEDLINKS: - if IEnhancedLinksEnabled.providedBy(self.context): - result.update( - { - "getObjSize": human_readable_size(size), - "enhanced_links_enabled": True, - } - ) + if IEnhancedLinksEnabled.providedBy(self.context): + result.update( + { + "getObjSize": human_readable_size(size), + "enhanced_links_enabled": True, + } + ) return json_compatible(result) @@ -117,14 +111,13 @@ def get_file_view_mode(self, content_type): class ImageFieldSerializer(BaseImageFieldSerializer): def __call__(self): result = super().__call__() - if HAS_ENHANCEDLINKS: - if IEnhancedLinksEnabled.providedBy(self.context): - result.update( - { - "getObjSize": human_readable_size(result["size"]), - "enhanced_links_enabled": True, - } - ) + if IEnhancedLinksEnabled.providedBy(self.context): + result.update( + { + "getObjSize": human_readable_size(result["size"]), + "enhanced_links_enabled": True, + } + ) return result From a3d027903d77131a91a99d2ef6e57751191b7614 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 31 Jan 2024 14:50:15 +0100 Subject: [PATCH 15/23] enhance Bandi serializer for enhancedlinks features --- src/design/plone/contenttypes/restapi/serializers/bando.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/design/plone/contenttypes/restapi/serializers/bando.py b/src/design/plone/contenttypes/restapi/serializers/bando.py index 9e463ad0..c3354e70 100644 --- a/src/design/plone/contenttypes/restapi/serializers/bando.py +++ b/src/design/plone/contenttypes/restapi/serializers/bando.py @@ -19,6 +19,11 @@ def get_approfondimenti(self, bando_view): contents = bando_view.retrieveContentsOfFolderDeepening(folder["path"]) if not contents: continue + # fix results for enhancedlinks + for content in contents: + content["getObjSize"] = content.get("filesize", "") + content["mime_type"] = content.get("content-type", "") + content["enhanced_links_enabled"] = "filesize" in content folder.update({"children": contents}) results.append(folder) return results From 4b6eb12108a201806716812942bd647ff87d3548 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 7 Feb 2024 14:16:39 +0100 Subject: [PATCH 16/23] fix check --- src/design/plone/contenttypes/restapi/serializers/dxfields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/design/plone/contenttypes/restapi/serializers/dxfields.py b/src/design/plone/contenttypes/restapi/serializers/dxfields.py index ef0be61e..fb11bef5 100644 --- a/src/design/plone/contenttypes/restapi/serializers/dxfields.py +++ b/src/design/plone/contenttypes/restapi/serializers/dxfields.py @@ -111,7 +111,7 @@ def get_file_view_mode(self, content_type): class ImageFieldSerializer(BaseImageFieldSerializer): def __call__(self): result = super().__call__() - if IEnhancedLinksEnabled.providedBy(self.context): + if result and IEnhancedLinksEnabled.providedBy(self.context): result.update( { "getObjSize": human_readable_size(result["size"]), From 1fe7f29504957f5cf842d4a358723c1d4d1b9cd9 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 12 Feb 2024 16:19:09 +0100 Subject: [PATCH 17/23] Fix in @scadenziario endpoint: return future events if afterToday criteria is set --- CHANGES.rst | 3 +- .../restapi/services/scadenziario/post.py | 8 +- .../tests/test_service_scadenziario.py | 89 +++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/design/plone/contenttypes/tests/test_service_scadenziario.py diff --git a/CHANGES.rst b/CHANGES.rst index c0d5ecc2..65f15808 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,8 @@ Changelog 6.1.14 (unreleased) ------------------- -- Nothing changed yet. +- Fix in @scadenziario endpoint: return future events if afterToday criteria is set. + [cekk] 6.1.13 (2024-02-08) 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_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"), + ) From 3944b7ff227e499cbcb86a6a957b782f68768722 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Wed, 28 Feb 2024 15:12:07 +0100 Subject: [PATCH 18/23] fix upgrade-steps --- .../profiles/default/metadata.xml | 2 +- .../contenttypes/upgrades/configure.zcml | 12 ++++-- .../plone/contenttypes/upgrades/upgrades.py | 40 +++++++++---------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/design/plone/contenttypes/profiles/default/metadata.xml b/src/design/plone/contenttypes/profiles/default/metadata.xml index 02613dde..a1d80769 100644 --- a/src/design/plone/contenttypes/profiles/default/metadata.xml +++ b/src/design/plone/contenttypes/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 7031 + 7100 profile-redturtle.bandi:default profile-collective.venue:default diff --git a/src/design/plone/contenttypes/upgrades/configure.zcml b/src/design/plone/contenttypes/upgrades/configure.zcml index f3397dc4..894614df 100644 --- a/src/design/plone/contenttypes/upgrades/configure.zcml +++ b/src/design/plone/contenttypes/upgrades/configure.zcml @@ -817,9 +817,6 @@ title="Add new field in settings" handler=".upgrades.update_registry" /> - + + + diff --git a/src/design/plone/contenttypes/upgrades/upgrades.py b/src/design/plone/contenttypes/upgrades/upgrades.py index c34b734b..af7bbfa6 100644 --- a/src/design/plone/contenttypes/upgrades/upgrades.py +++ b/src/design/plone/contenttypes/upgrades/upgrades.py @@ -1579,26 +1579,6 @@ def update_pdc_with_pdc_desc(context): logger.info("Ends of update") -def to_7030(context): - installOrReinstallProduct(api.portal.get(), "collective.volto.enhancedlinks") - # add behavior to modulo - portal_types = api.portal.get_tool(name="portal_types") - modulo_behaviors = [x for x in portal_types["Modulo"].behaviors] - if "volto.enhanced_links_enabled" not in modulo_behaviors: - modulo_behaviors.append("volto.enhanced_links_enabled") - portal_types["Modulo"].behaviors = tuple(modulo_behaviors) - - # update index/metadata - brains = api.content.find(portal_type=["File", "Image", "Modulo"]) - tot = len(brains) - i = 0 - for brain in brains: - i += 1 - if i % 100 == 0: - logger.info("Progress: {}/{}".format(i, tot)) - brain.getObject().reindexObject(idxs=["enhanced_links_enabled"]) - - def add_canale_digitale_link_index(context): update_catalog(context) update_registry(context) @@ -1616,3 +1596,23 @@ def to_7031(context): for ptype in ["News Item"]: portal_types[ptype].default_view = "view" portal_types[ptype].view_methods = ["view"] + + +def to_7100(context): + installOrReinstallProduct(api.portal.get(), "collective.volto.enhancedlinks") + # add behavior to modulo + portal_types = api.portal.get_tool(name="portal_types") + modulo_behaviors = [x for x in portal_types["Modulo"].behaviors] + if "volto.enhanced_links_enabled" not in modulo_behaviors: + modulo_behaviors.append("volto.enhanced_links_enabled") + portal_types["Modulo"].behaviors = tuple(modulo_behaviors) + + # update index/metadata + brains = api.content.find(portal_type=["File", "Image", "Modulo"]) + tot = len(brains) + i = 0 + for brain in brains: + i += 1 + if i % 100 == 0: + logger.info("Progress: {}/{}".format(i, tot)) + brain.getObject().reindexObject(idxs=["enhanced_links_enabled"]) From aeabe200fe6eedecc576a88b730b6fefec7764f4 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 4 Mar 2024 14:00:16 +0100 Subject: [PATCH 19/23] removed unused logger --- src/design/plone/contenttypes/restapi/serializers/summary.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/design/plone/contenttypes/restapi/serializers/summary.py b/src/design/plone/contenttypes/restapi/serializers/summary.py index ca195a9d..055ba38e 100644 --- a/src/design/plone/contenttypes/restapi/serializers/summary.py +++ b/src/design/plone/contenttypes/restapi/serializers/summary.py @@ -239,11 +239,6 @@ def get_design_meta_type(self): ttool[self.context.portal_type].Title(), context=self.request ) else: - logger.warning( - "missing portal_type %s for %s", - self.context.portal_type, - self.context.absolute_url(), - ) return self.context.portal_type def expand_tassonomia_argomenti(self): From d4821fd03ed2da3c271fbf010a582cf531284fbc Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 4 Mar 2024 14:24:45 +0100 Subject: [PATCH 20/23] fix tests --- src/design/plone/contenttypes/tests/test_ct_event.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/design/plone/contenttypes/tests/test_ct_event.py b/src/design/plone/contenttypes/tests/test_ct_event.py index a0a527e8..ebc063fe 100644 --- a/src/design/plone/contenttypes/tests/test_ct_event.py +++ b/src/design/plone/contenttypes/tests/test_ct_event.py @@ -117,6 +117,7 @@ def test_event_required_fields(self): "tassonomia_argomenti", "tipologia_evento", "start", + "prezzo", "end", "descrizione_estesa", "descrizione_destinatari", @@ -150,7 +151,7 @@ def test_event_fields_default_fieldset(self): "recurrence", "sottotitolo", "tipologia_evento", - ] + ], # should be like this with SchemaTweaks # [ # "title", @@ -281,7 +282,7 @@ def test_event_fields_categorization_fieldset(self): resp = self.api_session.get("@types/Event").json() self.assertEqual( resp["fieldsets"][7]["fields"], - ["subjects", "language", "relatedItems"] + ["subjects", "language", "relatedItems"], # should be like this with SchemaTweaks # ["subjects", "language"], ) From 92ece11dd6d3851c48ad2f4a79028ccbbd1ffc3d Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 4 Mar 2024 15:39:20 +0100 Subject: [PATCH 21/23] standardize subfolders creation in events --- CHANGES.rst | 16 +- src/design/plone/contenttypes/events/bando.py | 19 -- .../plone/contenttypes/events/common.py | 169 ++++++++++++++++++ .../plone/contenttypes/events/configure.zcml | 56 +----- .../plone/contenttypes/events/documento.py | 36 ---- .../plone/contenttypes/events/evento.py | 88 --------- .../plone/contenttypes/events/incarico.py | 32 ---- src/design/plone/contenttypes/events/luogo.py | 30 ---- .../events/notizie_e_comunicati_stampa.py | 33 ---- .../plone/contenttypes/events/persona.py | 53 ------ .../plone/contenttypes/events/pratica.py | 20 --- .../plone/contenttypes/events/servizio.py | 29 --- .../events/unita_organizzativa.py | 35 ---- 13 files changed, 179 insertions(+), 437 deletions(-) delete mode 100644 src/design/plone/contenttypes/events/bando.py delete mode 100644 src/design/plone/contenttypes/events/documento.py delete mode 100644 src/design/plone/contenttypes/events/evento.py delete mode 100644 src/design/plone/contenttypes/events/luogo.py delete mode 100644 src/design/plone/contenttypes/events/notizie_e_comunicati_stampa.py delete mode 100644 src/design/plone/contenttypes/events/persona.py delete mode 100644 src/design/plone/contenttypes/events/pratica.py delete mode 100644 src/design/plone/contenttypes/events/servizio.py delete mode 100644 src/design/plone/contenttypes/events/unita_organizzativa.py diff --git a/CHANGES.rst b/CHANGES.rst index 8feb4863..0636fed2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,10 @@ Changelog 6.1.15 (unreleased) ------------------- -- Fix in @scadenziario endpoint: return future events if afterToday criteria is set. +- Remove unused behavior (design.plone.contenttypes.behavior.geolocation_uo). + [cekk] +- Move id/title mapping for automatic created children (with events) in separate variables, + so they can be easily overrided. [cekk] @@ -20,7 +23,6 @@ Changelog [eikichi18] - 6.1.13 (2024-02-08) ------------------- @@ -43,13 +45,7 @@ Changelog - Fixed script to update pdc with description [eikichi18] -- Add collective.volto.enhancedlinks dependency (needed for slate integration). - [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. +- Add getObjSize info in File field serializer. [cekk] - Add new flag in settings needed to choose to show or not auto-generated footer columns. [cekk] @@ -72,8 +68,6 @@ Changelog 6.1.9 (2024-01-11) ------------------ -- Do not show fieldsets with no visible fields in @types endpoint. - [cekk] - Add UID to UOJSONSummarySerializer [eikichi18] diff --git a/src/design/plone/contenttypes/events/bando.py b/src/design/plone/contenttypes/events/bando.py deleted file mode 100644 index 858b25a3..00000000 --- a/src/design/plone/contenttypes/events/bando.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -from plone import api - - -def bandoCreateHandler(bando, event): - """ """ - folders = [ - {"id": "documenti", "title": "Documenti"}, - {"id": "comunicazioni", "title": "Comunicazioni"}, - {"id": "esiti", "title": "Esiti"}, - ] - for mapping in folders: - if mapping["id"] not in bando: - api.content.create( - type="Bando Folder Deepening", - title=mapping["title"], - id=mapping["id"], - container=bando, - ) diff --git a/src/design/plone/contenttypes/events/common.py b/src/design/plone/contenttypes/events/common.py index 2fe82574..51b7c49c 100644 --- a/src/design/plone/contenttypes/events/common.py +++ b/src/design/plone/contenttypes/events/common.py @@ -1,4 +1,142 @@ # -*- coding: utf-8 -*- +from design.plone.contenttypes.interfaces import IDesignPloneContenttypesLayer +from design.plone.contenttypes.utils import create_default_blocks +from plone import api +from Products.CMFPlone.interfaces import ISelectableConstrainTypes + + +SUBFOLDERS_MAPPING = { + "Bando": [ + {"id": "documenti", "title": "Documenti", "type": "Bando Folder Deepening"}, + { + "id": "comunicazioni", + "title": "Comunicazioni", + "type": "Bando Folder Deepening", + }, + {"id": "esiti", "title": "Esiti", "type": "Bando Folder Deepening"}, + ], + "Documento": [ + { + "id": "multimedia", + "title": "Multimedia", + "type": "Document", + "allowed_types": ("Image",), + }, + ], + "Event": [ + { + "id": "immagini", + "title": "Immagini", + "allowed_types": ("Image", "Link"), + "publish": True, + }, + { + "id": "video", + "title": "Video", + "allowed_types": ("Link",), + "publish": True, + }, + { + "id": "sponsor_evento", + "title": "Sponsor Evento", + "allowed_types": ("Link",), + "publish": True, + }, + { + "id": "documenti", + "title": "Allegati", + "allowed_types": ("File",), + "publish": True, + }, + ], + "Incarico": [ + {"id": "compensi-file", "title": "Compensi", "allowed": ("File",)}, + { + "id": "importi-di-viaggio-e-o-servizi", + "title": "Importi di viaggio e/o servizi", + "allowed_types": ("File",), + }, + ], + "Venue": [ + { + "id": "multimedia", + "title": "Multimedia", + "type": "Folder", + "allowed_types": ( + "Image", + "Link", + ), + "publish": True, + } + ], + "News Item": [ + { + "id": "multimedia", + "title": "Multimedia", + "allowed_types": ( + "Image", + "Link", + ), + }, + { + "id": "documenti-allegati", + "title": "Documenti allegati", + "allowed_types": ( + "File", + "Image", + ), + }, + ], + "Persona": [ + { + "id": "foto-e-attivita-politica", + "title": "Foto e attività politica", + "allowed_types": ("Image",), + }, + { + "id": "curriculum-vitae", + "title": "Curriculum vitae", + "allowed_types": ("File",), + }, + { + "id": "situazione-patrimoniale", + "title": "Situazione patrimoniale", + "allowed_types": ("File",), + }, + { + "id": "dichiarazione-dei-redditi", + "title": "Dichiarazione dei redditi", + "allowed_types": ("File",), + }, + { + "id": "spese-elettorali", + "title": "Spese elettorali", + "allowed_types": ("File",), + }, + { + "id": "variazione-situazione-patrimoniale", + "title": "Variazione situazione patrimoniale", + "allowed_types": ("File",), + }, + {"id": "altre-cariche", "title": "Altre cariche", "allowed_types": ("File",)}, + {"id": "incarichi", "title": "Incarichi", "allowed_types": ("Incarico",)}, + ], + "Pratica": [ + { + "id": "allegati", + "title": "Allegati", + "type": "Folder", + "allowed_types": ("File",), + } + ], + "Servizio": [ + {"id": "modulistica", "title": "Modulistica", "contains": ("File", "Link")}, + {"id": "allegati", "title": "Allegati", "contains": ("File", "Link")}, + ], + "UnitaOrganizzativa": [ + {"id": "allegati", "title": "Allegati", "contains": ("File",)}, + ], +} def onModify(context, event): @@ -8,3 +146,34 @@ def onModify(context, event): ) or "IDublinCore.title" in getattr(description, "attributes", []): for child in context.listFolderContents(): child.reindexObject(idxs=["parent"]) + + +def createSubfolders(context, event): + """ + Create subfolders structure based on a portal_type mapping + """ + if not IDesignPloneContenttypesLayer.providedBy(context.REQUEST): + return + + subfolders_mapping = SUBFOLDERS_MAPPING.get(context.portal_type, []) + if not subfolders_mapping: + return + for mapping in subfolders_mapping: + if mapping["id"] not in context.keys(): + child = api.content.create( + container=context, + type=mapping.get("type", "Document"), + title=mapping["title"], + id=mapping["id"], + ) + create_default_blocks(context=child) + + # select constraints + if mapping.get("allowed_types", ()): + constraintsChild = ISelectableConstrainTypes(child) + constraintsChild.setConstrainTypesMode(1) + constraintsChild.setLocallyAllowedTypes(mapping["allowed_types"]) + + if mapping.get("publish", False): + with api.env.adopt_roles(["Reviewer"]): + api.content.transition(obj=child, transition="publish") diff --git a/src/design/plone/contenttypes/events/configure.zcml b/src/design/plone/contenttypes/events/configure.zcml index b5b62c8c..2752fbf2 100644 --- a/src/design/plone/contenttypes/events/configure.zcml +++ b/src/design/plone/contenttypes/events/configure.zcml @@ -5,46 +5,6 @@ i18n_domain="design.plone.contenttypes" > - - - - - - - - - - - + diff --git a/src/design/plone/contenttypes/events/documento.py b/src/design/plone/contenttypes/events/documento.py deleted file mode 100644 index e8cc971d..00000000 --- a/src/design/plone/contenttypes/events/documento.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -from design.plone.contenttypes.utils import create_default_blocks -from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - - -def documentoCreateHandler(documento, event): - """ - Complete content type Documento setup on added event, generating - missing folders, fields, etc. - - @param documento: Content item - - @param event: Event that triggers the method (onAdded event) - """ - if "multimedia" in documento.keys(): - # we are copying or moving it - return - - documentoConstraints = ISelectableConstrainTypes(documento) - documentoConstraints.setConstrainTypesMode(1) - documentoConstraints.setLocallyAllowedTypes(("Document",)) - - # create support folder - multimedia = api.content.create( - type="Document", title="Multimedia", container=documento - ) - create_default_blocks(context=multimedia) - - multimediaConstraints = ISelectableConstrainTypes(multimedia) - multimediaConstraints.setConstrainTypesMode(1) - multimediaConstraints.setLocallyAllowedTypes(("Image",)) - - documentoConstraints = ISelectableConstrainTypes(documento) - documentoConstraints.setConstrainTypesMode(1) - documentoConstraints.setLocallyAllowedTypes(("Modulo", "Link")) diff --git a/src/design/plone/contenttypes/events/evento.py b/src/design/plone/contenttypes/events/evento.py deleted file mode 100644 index 50173d1f..00000000 --- a/src/design/plone/contenttypes/events/evento.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -from design.plone.contenttypes.interfaces import IDesignPloneContenttypesLayer -from design.plone.contenttypes.utils import create_default_blocks -from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - - -GALLERIA_MAPPING = {"id": "immagini", "title": "Immagini"} - -DOCUMENTI_TITLE = "Allegati" - - -def eventoCreateHandler(evento, event): - """ - Complete content type evento setup on added event, generating - missing folders, fields, etc. - - @param evento: Content item - - @param event: Event that triggers the method (onAdded event) - """ - if not IDesignPloneContenttypesLayer.providedBy(evento.REQUEST): - return - if GALLERIA_MAPPING["id"] not in evento.keys(): - galleria = api.content.create( - container=evento, - type="Document", - title=GALLERIA_MAPPING["title"], - id=GALLERIA_MAPPING["id"], - ) - create_default_blocks(context=galleria) - - # select constraints - constraintsGalleria = ISelectableConstrainTypes(galleria) - constraintsGalleria.setConstrainTypesMode(1) - constraintsGalleria.setLocallyAllowedTypes(("Image", "Link")) - - with api.env.adopt_roles(["Reviewer"]): - api.content.transition(obj=galleria, transition="publish") - - if "video" not in evento.keys(): - galleria_video = api.content.create( - container=evento, - type="Document", - title="Video", - id="video", - ) - create_default_blocks(context=galleria_video) - - # select constraints - constraintsGalleriaVideo = ISelectableConstrainTypes(galleria_video) - constraintsGalleriaVideo.setConstrainTypesMode(1) - constraintsGalleriaVideo.setLocallyAllowedTypes(("Link",)) - - with api.env.adopt_roles(["Reviewer"]): - api.content.transition(obj=galleria_video, transition="publish") - - if "sponsor_evento" not in evento.keys(): - sponsor = api.content.create( - container=evento, - type="Document", - title="Sponsor Evento", - id="sponsor_evento", - ) - create_default_blocks(context=sponsor) - - constraintsSponsor = ISelectableConstrainTypes(sponsor) - constraintsSponsor.setConstrainTypesMode(1) - constraintsSponsor.setLocallyAllowedTypes(("Link",)) - - with api.env.adopt_roles(["Reviewer"]): - api.content.transition(obj=sponsor, transition="publish") - - if "documenti" not in evento.keys(): - documenti = api.content.create( - container=evento, - type="Document", - title=DOCUMENTI_TITLE, - id="documenti", - ) - create_default_blocks(context=documenti) - - constraintsDocumenti = ISelectableConstrainTypes(documenti) - constraintsDocumenti.setConstrainTypesMode(1) - constraintsDocumenti.setLocallyAllowedTypes(("File",)) - - with api.env.adopt_roles(["Reviewer"]): - api.content.transition(obj=documenti, transition="publish") diff --git a/src/design/plone/contenttypes/events/incarico.py b/src/design/plone/contenttypes/events/incarico.py index 6b077b49..34368b77 100644 --- a/src/design/plone/contenttypes/events/incarico.py +++ b/src/design/plone/contenttypes/events/incarico.py @@ -1,37 +1,5 @@ # -*- coding: utf-8 -*- -from design.plone.contenttypes.utils import create_default_blocks from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - - -def incaricoCreateHandler(incarico, event): - """ - Complete content type incarico setup on added event, generating - missing folders, fields, etc. - - @param incarico: Content item - - @param event: Event that triggers the method (onAdded event) - """ - - FOLDERS = [ - {"id": "compensi-file", "title": "Compensi", "contains": ("File",)}, - { - "id": "importi-di-viaggio-e-o-servizi", - "title": "Importi di viaggio e/o servizi", - "contains": ("File",), - }, - ] - for folder in FOLDERS: - if folder["id"] in incarico: - continue - suboject = api.content.create( - type="Document", id=folder["id"], title=folder["title"], container=incarico - ) - create_default_blocks(context=suboject) - subobjectConstraints = ISelectableConstrainTypes(suboject) - subobjectConstraints.setConstrainTypesMode(1) - subobjectConstraints.setLocallyAllowedTypes(folder["contains"]) def modify_incarico(obj, event): diff --git a/src/design/plone/contenttypes/events/luogo.py b/src/design/plone/contenttypes/events/luogo.py deleted file mode 100644 index 42bf0e47..00000000 --- a/src/design/plone/contenttypes/events/luogo.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -from Products.CMFPlone.interfaces import ISelectableConstrainTypes -from Products.CMFPlone.utils import _createObjectByType - - -def luogoCreateHandler(luogo, event): - """ - Complete content type luogo setup on added event, generating - missing folders, fields, etc. - - @param luogo: Content item - - @param event: Event that triggers the method (onAdded event) - """ - folder_id = "multimedia" - if folder_id in luogo: - return - folder = _createObjectByType("Folder", luogo, "multimedia") - folder.title = "Multimedia" - folder.reindexObject(idxs=["Title"]) - constraints = ISelectableConstrainTypes(folder) - constraints.setConstrainTypesMode(1) - constraints.setLocallyAllowedTypes( - ( - "Image", - "Link", - ) - ) - - # non dovrebbe essere cancellabile diff --git a/src/design/plone/contenttypes/events/notizie_e_comunicati_stampa.py b/src/design/plone/contenttypes/events/notizie_e_comunicati_stampa.py deleted file mode 100644 index 053928e3..00000000 --- a/src/design/plone/contenttypes/events/notizie_e_comunicati_stampa.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -from design.plone.contenttypes.utils import create_default_blocks -from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - - -def notiziaCreateHandler(notizia, event): - """ - Complete content type notizia setup on added event, generating - missing folders, fields, etc. - - @param notizia: Content item - - @param event: Event that triggers the method (onAdded event) - """ - - if "multimedia" not in notizia.keys(): - multimedia = api.content.create( - type="Document", title="Multimedia", container=notizia - ) - create_default_blocks(context=multimedia) - constraintsMultimedia = ISelectableConstrainTypes(multimedia) - constraintsMultimedia.setConstrainTypesMode(1) - constraintsMultimedia.setLocallyAllowedTypes(("Link", "Image")) - - if "documenti-allegati" not in notizia.keys(): - documenti = api.content.create( - type="Document", title="Documenti allegati", container=notizia - ) - create_default_blocks(context=documenti) - constraintsDocumenti = ISelectableConstrainTypes(documenti) - constraintsDocumenti.setConstrainTypesMode(1) - constraintsDocumenti.setLocallyAllowedTypes(("File", "Image")) diff --git a/src/design/plone/contenttypes/events/persona.py b/src/design/plone/contenttypes/events/persona.py deleted file mode 100644 index e9aef428..00000000 --- a/src/design/plone/contenttypes/events/persona.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -from design.plone.contenttypes.utils import create_default_blocks -from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - -FOLDERS = [ - { - "id": "foto-e-attivita-politica", - "title": "Foto e attività politica", - "contains": ("Image",), - }, - {"id": "curriculum-vitae", "title": "Curriculum vitae", "contains": ("File",)}, - { - "id": "situazione-patrimoniale", - "title": "Situazione patrimoniale", - "contains": ("File",), - }, - { - "id": "dichiarazione-dei-redditi", - "title": "Dichiarazione dei redditi", - "contains": ("File",), - }, - {"id": "spese-elettorali", "title": "Spese elettorali", "contains": ("File",)}, - { - "id": "variazione-situazione-patrimoniale", - "title": "Variazione situazione patrimoniale", - "contains": ("File",), - }, - {"id": "altre-cariche", "title": "Altre cariche", "contains": ("File",)}, - {"id": "incarichi", "title": "Incarichi", "contains": ("Incarico",)}, -] - - -def personaCreateHandler(persona, event): - """ - Complete content type Persona setup on added event, generating - missing folders, fields, etc. - - @param persona: Content item - - @param event: Event that triggers the method (onAdded event) - """ - - for folder in FOLDERS: - if folder["id"] in persona: - continue - suboject = api.content.create( - type="Document", id=folder["id"], title=folder["title"], container=persona - ) - create_default_blocks(context=suboject) - subobjectConstraints = ISelectableConstrainTypes(suboject) - subobjectConstraints.setConstrainTypesMode(1) - subobjectConstraints.setLocallyAllowedTypes(folder["contains"]) diff --git a/src/design/plone/contenttypes/events/pratica.py b/src/design/plone/contenttypes/events/pratica.py deleted file mode 100644 index bf44dda7..00000000 --- a/src/design/plone/contenttypes/events/pratica.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - - -def praticaCreateHandler(pratica, event): - """ - Complete content type Pratica setup on added event, generating - missing folders, fields, etc. - - @param pratica: Content item - - @param event: Event that triggers the method (onAdded event) - """ - - allegati = api.content.create(type="Folder", title="Allegati", container=pratica) - - allegatiConstraints = ISelectableConstrainTypes(allegati) - allegatiConstraints.setConstrainTypesMode(1) - allegatiConstraints.setLocallyAllowedTypes(("File",)) diff --git a/src/design/plone/contenttypes/events/servizio.py b/src/design/plone/contenttypes/events/servizio.py deleted file mode 100644 index 1a37f81e..00000000 --- a/src/design/plone/contenttypes/events/servizio.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- -from design.plone.contenttypes.utils import create_default_blocks -from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - - -def servizioCreateHandler(servizio, event): - """ - Complete content type Servizio setup on added event, generating - missing folders, fields, etc. - - @param servizio: Content item - - @param event: Event that triggers the method (onAdded event) - """ - - for folder in [ - {"id": "modulistica", "title": "Modulistica", "contains": ("File", "Link")}, - {"id": "allegati", "title": "Allegati", "contains": ("File", "Link")}, - ]: - if folder["id"] not in servizio.keys(): - child = api.content.create( - type="Document", title=folder["title"], container=servizio - ) - create_default_blocks(context=child) - - childConstraints = ISelectableConstrainTypes(child) - childConstraints.setConstrainTypesMode(1) - childConstraints.setLocallyAllowedTypes(folder["contains"]) diff --git a/src/design/plone/contenttypes/events/unita_organizzativa.py b/src/design/plone/contenttypes/events/unita_organizzativa.py deleted file mode 100644 index ec11a746..00000000 --- a/src/design/plone/contenttypes/events/unita_organizzativa.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -from design.plone.contenttypes.utils import create_default_blocks -from plone import api -from Products.CMFPlone.interfaces import ISelectableConstrainTypes - -import logging - - -logger = logging.getLogger(__name__) - - -def unitaOrganizzativaCreateHandler(unitaOrganizzativa, event): - """ - Complete content type UnitaOrganizzativa setup on added event, generating - missing folders, fields, etc. - - @param unitaOrganizzativa: Content item - - @param event: Event that triggers the method (onAdded event) - """ - if "allegati" in unitaOrganizzativa.keys(): - return - try: - allegati = api.content.create( - type="Document", title="Allegati", container=unitaOrganizzativa - ) - except AttributeError as e: - # problems with tests in design.plone.policy - logger.exception(e) - return - - create_default_blocks(context=allegati) - allegatiConstraints = ISelectableConstrainTypes(allegati) - allegatiConstraints.setConstrainTypesMode(1) - allegatiConstraints.setLocallyAllowedTypes(("File",)) From e8087f093945a7cfd59c1d4e7714e52c778f6112 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 4 Mar 2024 15:45:44 +0100 Subject: [PATCH 22/23] update changelog --- CHANGES.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 0636fed2..bc479736 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -6,10 +6,12 @@ Changelog - Remove unused behavior (design.plone.contenttypes.behavior.geolocation_uo). [cekk] -- Move id/title mapping for automatic created children (with events) in separate variables, - so they can be easily overrided. +- Standardize subfolders creations in events. + [cekk] +- Do not return a fieldset if it has all fields hidden (maybe after a schema tweak). + [cekk] +- Improve types test for their schema, required fields, fieldsets. [cekk] - 6.1.14 (2024-02-20) ------------------- From 2e08c7f85ed6ffff23b3f02d52676edf0d078da9 Mon Sep 17 00:00:00 2001 From: Andrea Cecchi Date: Mon, 4 Mar 2024 15:50:48 +0100 Subject: [PATCH 23/23] zpretty --- src/design/plone/contenttypes/upgrades/configure.zcml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/design/plone/contenttypes/upgrades/configure.zcml b/src/design/plone/contenttypes/upgrades/configure.zcml index 894614df..53231884 100644 --- a/src/design/plone/contenttypes/upgrades/configure.zcml +++ b/src/design/plone/contenttypes/upgrades/configure.zcml @@ -835,6 +835,7 @@ > + handler=".upgrades.to_7100" + />