From 75b4b9a62f692ac30acd9b51633c27860054f15c Mon Sep 17 00:00:00 2001 From: Daniele Andreotti Date: Fri, 5 Jul 2024 15:18:12 +0200 Subject: [PATCH] added criteria, indexers and vocabularies --- .../contenttypes/behaviors/argomenti.py | 26 -- src/iosanita/contenttypes/events/__init__.py | 0 src/iosanita/contenttypes/events/common.py | 229 ++++++++++++++++++ .../contenttypes/events/configure.zcml | 25 ++ src/iosanita/contenttypes/events/events.py | 8 + .../contenttypes/indexers/__init__.py | 0 src/iosanita/contenttypes/indexers/common.py | 43 ++++ .../contenttypes/indexers/configure.zcml | 34 +++ src/iosanita/contenttypes/indexers/events.py | 19 ++ src/iosanita/contenttypes/indexers/news.py | 32 +++ .../contenttypes/profiles/default/catalog.xml | 31 ++- .../profiles/default/registry/criteria.xml | 49 ++++ .../contenttypes/vocabularies/__init__.py | 0 .../contenttypes/vocabularies/configure.zcml | 12 + .../contenttypes/vocabularies/mockup.py | 49 ++++ .../vocabularies/reference_vocabularies.py | 55 +++++ 16 files changed, 583 insertions(+), 29 deletions(-) create mode 100644 src/iosanita/contenttypes/events/__init__.py create mode 100644 src/iosanita/contenttypes/events/common.py create mode 100644 src/iosanita/contenttypes/events/configure.zcml create mode 100644 src/iosanita/contenttypes/events/events.py create mode 100644 src/iosanita/contenttypes/indexers/__init__.py create mode 100644 src/iosanita/contenttypes/indexers/common.py create mode 100644 src/iosanita/contenttypes/indexers/configure.zcml create mode 100644 src/iosanita/contenttypes/indexers/events.py create mode 100644 src/iosanita/contenttypes/indexers/news.py create mode 100644 src/iosanita/contenttypes/profiles/default/registry/criteria.xml create mode 100644 src/iosanita/contenttypes/vocabularies/__init__.py create mode 100644 src/iosanita/contenttypes/vocabularies/configure.zcml create mode 100644 src/iosanita/contenttypes/vocabularies/mockup.py create mode 100644 src/iosanita/contenttypes/vocabularies/reference_vocabularies.py diff --git a/src/iosanita/contenttypes/behaviors/argomenti.py b/src/iosanita/contenttypes/behaviors/argomenti.py index 97dbb83..844c164 100644 --- a/src/iosanita/contenttypes/behaviors/argomenti.py +++ b/src/iosanita/contenttypes/behaviors/argomenti.py @@ -31,20 +31,6 @@ class IArgomentiSchema(model.Schema): required=False, default=[], ) - correlato_in_evidenza = RelationList( - title=_("correlato_in_evidenza_label", default="Correlato in evidenza"), - description=_( - "correlato_in_evidenza_help", - default="Seleziona un correlato da mettere in evidenza per questo" - " contenuto.", - ), - value_type=RelationChoice( - title=_("Correlato in evidenza"), - vocabulary="plone.app.vocabularies.Catalog", - ), - required=False, - default=[], - ) form.widget( "tassonomia_argomenti", @@ -54,12 +40,6 @@ class IArgomentiSchema(model.Schema): "selectableTypes": ["Pagina Argomento"], }, ) - form.widget( - "correlato_in_evidenza", - RelatedItemsFieldWidget, - vocabulary="plone.app.vocabularies.Catalog", - pattern_options={"maximumSelectionSize": 1}, - ) textindexer.searchable("tassonomia_argomenti") @@ -68,12 +48,6 @@ class IArgomentiSchema(model.Schema): class IArgomenti(IArgomentiSchema): """ """ - model.fieldset( - "correlati", - label=_("correlati_label", default="Contenuti collegati"), - fields=["correlato_in_evidenza"], - ) - @provider(IFormFieldProvider) class IArgomentiEvento(IArgomentiSchema): diff --git a/src/iosanita/contenttypes/events/__init__.py b/src/iosanita/contenttypes/events/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/iosanita/contenttypes/events/common.py b/src/iosanita/contenttypes/events/common.py new file mode 100644 index 0000000..70d69fb --- /dev/null +++ b/src/iosanita/contenttypes/events/common.py @@ -0,0 +1,229 @@ +# -*- 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": { + "content": [ + {"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": { + "content": [ + { + "id": "multimedia", + "title": "Multimedia", + "type": "Document", + "allowed_types": ("Image",), + }, + ], + }, + "Event": { + "content": [ + { + "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": { + "content": [ + {"id": "compensi-file", "title": "Compensi", "allowed": ("File",)}, + { + "id": "importi-di-viaggio-e-o-servizi", + "title": "Importi di viaggio e/o servizi", + "allowed_types": ("File",), + }, + ], + "allowed_types": [], + }, + "Venue": { + "content": [ + { + "id": "multimedia", + "title": "Multimedia", + "type": "Folder", + "allowed_types": ( + "Image", + "Link", + ), + "publish": True, + } + ], + }, + "News Item": { + "content": [ + { + "id": "multimedia", + "title": "Multimedia", + "allowed_types": ( + "Image", + "Link", + ), + }, + { + "id": "documenti-allegati", + "title": "Documenti allegati", + "allowed_types": ( + "File", + "Image", + ), + }, + ], + }, + "Persona": { + "content": [ + { + "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",)}, + { + "id": "altri-documenti", + "title": "Altri documenti", + "allowed_types": ("File", "Image", "Link"), + }, + ], + "allowed_types": [], + }, + "Pratica": { + "content": [ + { + "id": "allegati", + "title": "Allegati", + "type": "Folder", + "allowed_types": ("File",), + } + ], + }, + "Servizio": { + "content": [ + { + "id": "modulistica", + "title": "Modulistica", + "allowed_types": ("Link",), + }, + {"id": "allegati", "title": "Allegati", "allowed_types": ("File", "Link")}, + ], + }, + "UnitaOrganizzativa": { + "content": [ + {"id": "allegati", "title": "Allegati", "allowed_types": ("File",)}, + ], + }, +} + + +def onModify(context, event): + for description in event.descriptions: + if "IBasic.title" in getattr( + description, "attributes", [] + ) 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.get("content", {}): + if mapping["id"] not in context.keys(): + portal_type = mapping.get("type", "Document") + child = api.content.create( + container=context, + type=portal_type, + title=mapping["title"], + id=mapping["id"], + ) + if portal_type == "Document": + create_default_blocks(context=child) + + if portal_type in ["Folder", "Document"]: + child.exclude_from_search = True + child.reindexObject(idxs=["exclude_from_search"]) + # select constraints + if mapping.get("allowed_types", ()): + constraints_child = ISelectableConstrainTypes(child) + constraints_child.setConstrainTypesMode(1) + constraints_child.setLocallyAllowedTypes(mapping["allowed_types"]) + + if mapping.get("publish", False): + with api.env.adopt_roles(["Reviewer"]): + api.content.transition(obj=child, transition="publish") + + allowed_types = subfolders_mapping.get("allowed_types", None) + if allowed_types is not None and not isinstance(allowed_types, list): + raise ValueError("Subfolder map is not well formed") + + if isinstance(allowed_types, list): + constraints_context = ISelectableConstrainTypes(context) + constraints_context.setConstrainTypesMode(1) + constraints_context.setLocallyAllowedTypes(allowed_types) diff --git a/src/iosanita/contenttypes/events/configure.zcml b/src/iosanita/contenttypes/events/configure.zcml new file mode 100644 index 0000000..4eef01c --- /dev/null +++ b/src/iosanita/contenttypes/events/configure.zcml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/src/iosanita/contenttypes/events/events.py b/src/iosanita/contenttypes/events/events.py new file mode 100644 index 0000000..1afaab7 --- /dev/null +++ b/src/iosanita/contenttypes/events/events.py @@ -0,0 +1,8 @@ +from Acquisition import aq_inner, aq_parent + + +def EventModified(dx_event, event): + parent = aq_parent(aq_inner(dx_event)) + if parent.portal_type == "Event": + parent.reindexObject(idxs=["rassegna"]) + return diff --git a/src/iosanita/contenttypes/indexers/__init__.py b/src/iosanita/contenttypes/indexers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/iosanita/contenttypes/indexers/common.py b/src/iosanita/contenttypes/indexers/common.py new file mode 100644 index 0000000..327f7a5 --- /dev/null +++ b/src/iosanita/contenttypes/indexers/common.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +from plone.dexterity.interfaces import IDexterityContent +from plone.indexer.decorator import indexer + + +@indexer(IDexterityContent) +def tassonomia_argomenti(context, **kw): + return [ + x.to_object.Title() + for x in getattr(context.aq_base, "tassonomia_argomenti", []) + if x.to_object + ] + + +@indexer(IDexterityContent) +def tassonomia_argomenti_uid(context, **kw): + return [ + x.to_object.UID() + for x in getattr(context.aq_base, "tassonomia_argomenti", []) + if x.to_object + ] + + +@indexer(IDexterityContent) +def ufficio_responsabile(context, **kw): + uffici = getattr(context.aq_base, "ufficio_responsabile", []) + return [ufficio.UID() for ufficio in filter(bool, [x.to_object for x in uffici])] + + +@indexer(IDexterityContent) +def parent(context): + obj_parent = context.aq_parent + return { + "title": obj_parent.Title(), + "UID": obj_parent.UID(), + "@id": obj_parent.absolute_url(), + "@type": obj_parent.portal_type, + } + + +@indexer(IDexterityContent) +def exclude_from_search(context): + return getattr(context.aq_base, "exclude_from_search", False) diff --git a/src/iosanita/contenttypes/indexers/configure.zcml b/src/iosanita/contenttypes/indexers/configure.zcml new file mode 100644 index 0000000..b63eea2 --- /dev/null +++ b/src/iosanita/contenttypes/indexers/configure.zcml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + diff --git a/src/iosanita/contenttypes/indexers/events.py b/src/iosanita/contenttypes/indexers/events.py new file mode 100644 index 0000000..6a22cb4 --- /dev/null +++ b/src/iosanita/contenttypes/indexers/events.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from plone.app.contenttypes.interfaces import IEvent +from plone.indexer.decorator import indexer + + +@indexer(IEvent) +def event_location(context, **kw): + """ """ + strutture_correlate = [x.to_object for x in context.strutture_correlate] + strutture_correlate = filter(bool, strutture_correlate) + strutture_correlate_title = [x.UID() for x in strutture_correlate] + return strutture_correlate_title + + +@indexer(IEvent) +def rassegna(context, **kw): + """ """ + children = context.values() + return "Event" in [child.portal_type for child in children] diff --git a/src/iosanita/contenttypes/indexers/news.py b/src/iosanita/contenttypes/indexers/news.py new file mode 100644 index 0000000..d3d8a75 --- /dev/null +++ b/src/iosanita/contenttypes/indexers/news.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +from plone.app.contenttypes.interfaces import INewsItem +from plone.indexer.decorator import indexer + + +@indexer(INewsItem) +def news_people(context, **kw): + people = context.a_cura_di_persone + return [persona.UID() for persona in filter(bool, [x.to_object for x in people])] + + +@indexer(INewsItem) +def news_uo(context, **kw): + unita_organizzative = context.a_cura_di + return [ + unita_organizzativa.UID() + for unita_organizzativa in filter( + bool, [x.to_object for x in unita_organizzative] + ) + ] + + +@indexer(INewsItem) +def news_service(context, **kw): + servizi = context.servizi_correlati + return [servizio.UID() for servizio in filter(bool, [x.to_object for x in servizi])] + + +@indexer(INewsItem) +def news_venue(context, **kw): + luoghi = context.luoghi_correlati + return [luogo.UID() for luogo in filter(bool, [x.to_object for x in luoghi])] diff --git a/src/iosanita/contenttypes/profiles/default/catalog.xml b/src/iosanita/contenttypes/profiles/default/catalog.xml index 0685c9d..9354784 100644 --- a/src/iosanita/contenttypes/profiles/default/catalog.xml +++ b/src/iosanita/contenttypes/profiles/default/catalog.xml @@ -1,4 +1,29 @@ - - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/iosanita/contenttypes/profiles/default/registry/criteria.xml b/src/iosanita/contenttypes/profiles/default/registry/criteria.xml new file mode 100644 index 0000000..27c3765 --- /dev/null +++ b/src/iosanita/contenttypes/profiles/default/registry/criteria.xml @@ -0,0 +1,49 @@ + + + + + Luogo evento + Luogo correlato legato all'evento + True + False + + plone.app.querystring.operation.selection.any + plone.app.querystring.operation.selection.all + + design.plone.vocabularies.event_location + Metadata + + + + + Tipologia di evento + + True + False + + plone.app.querystring.operation.selection.any + plone.app.querystring.operation.selection.all + + collective.taxonomy.tipologia_evento + Metadata + + + diff --git a/src/iosanita/contenttypes/vocabularies/__init__.py b/src/iosanita/contenttypes/vocabularies/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/iosanita/contenttypes/vocabularies/configure.zcml b/src/iosanita/contenttypes/vocabularies/configure.zcml new file mode 100644 index 0000000..a73803a --- /dev/null +++ b/src/iosanita/contenttypes/vocabularies/configure.zcml @@ -0,0 +1,12 @@ + + + + + + diff --git a/src/iosanita/contenttypes/vocabularies/mockup.py b/src/iosanita/contenttypes/vocabularies/mockup.py new file mode 100644 index 0000000..eb1d84c --- /dev/null +++ b/src/iosanita/contenttypes/vocabularies/mockup.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +from design.plone.contenttypes import _ +from plone.dexterity.interfaces import IDexterityContent +from zope.globalrequest import getRequest +from zope.interface import implementer +from zope.schema.interfaces import IVocabularyFactory +from zope.schema.vocabulary import SimpleTerm +from zope.schema.vocabulary import SimpleVocabulary + + +class VocabItem(object): + def __init__(self, token, value): + self.token = token + self.value = value + + +@implementer(IVocabularyFactory) +class Mockup(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("sony-a7r-iii", _("Sony Aplha 7R III")), + VocabItem("canon-5d-iv", _("Canon 5D IV")), + VocabItem("pippo", _("Pippo")), + VocabItem("pluto", _("Pluto")), + VocabItem("paperino", _("Paperino")), + VocabItem("giovanni", _("Giovanni")), + ] + + # Fix context if you are using the vocabulary in DataGridField. + # See https://github.com/collective/collective.z3cform.datagridfield/issues/31: # NOQA: 501 + if not IDexterityContent.providedBy(context): + req = getRequest() + context = req.PARENTS[0] + + # create a list of SimpleTerm items: + terms = [] + for item in items: + terms.append( + SimpleTerm(value=item.token, token=str(item.token), title=item.value) + ) + # Create a SimpleVocabulary from the terms list and return it: + return SimpleVocabulary(terms) + + +MockupFactory = Mockup() diff --git a/src/iosanita/contenttypes/vocabularies/reference_vocabularies.py b/src/iosanita/contenttypes/vocabularies/reference_vocabularies.py new file mode 100644 index 0000000..bfa2ef4 --- /dev/null +++ b/src/iosanita/contenttypes/vocabularies/reference_vocabularies.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +from Products.CMFCore.utils import getToolByName + + +try: + from plone.base.utils import safe_text +except ImportError: + from Products.CMFPlone.utils import safe_unicode as safe_text + +from zope.interface import implementer +from zope.schema.interfaces import IVocabularyFactory +from zope.schema.vocabulary import SimpleTerm +from zope.schema.vocabulary import SimpleVocabulary +from zope.component.hooks import getSite + + +class ReferencesVocabulary(object): + INDEX = "" + + def get_all_index_values(self): + index = self.catalog._catalog.getIndex(self.INDEX) + return list(index.uniqueValues()) + + def __call__(self, registry=None): + site = getSite() + self.catalog = getToolByName(site, "portal_catalog", None) + if self.catalog is None: + return SimpleVocabulary([]) + values = self.get_all_index_values() + brains = self.catalog(UID=values) + terms = [] + for brain in brains: + terms.append(SimpleTerm(brain.UID, brain.UID, safe_text(brain.Title))) + return SimpleVocabulary(terms) + + +@implementer(IVocabularyFactory) +class EventLocationVocabulary(ReferencesVocabulary): + INDEX = "event_location" + + +@implementer(IVocabularyFactory) +class OfficeLocationVocabulary(ReferencesVocabulary): + INDEX = "ufficio_responsabile" + + +@implementer(IVocabularyFactory) +class UOLocationVocabulary(ReferencesVocabulary): + INDEX = "uo_location" + + +EventLocationVocabularyFactory = EventLocationVocabulary() +OfficeLocationVocabularyFactory = OfficeLocationVocabulary() +UOLocationVocabularyFactory = UOLocationVocabulary()