From 328505ee396319b01306b93fed2f4195adc91931 Mon Sep 17 00:00:00 2001 From: Daniele Andreotti Date: Tue, 21 Nov 2023 17:09:59 +0100 Subject: [PATCH 1/4] Added utility views for Event --- CHANGES.rst | 3 +- .../browser/utils/check_eventi.py | 190 ++++++++++++++++++ .../contenttypes/browser/utils/configure.zcml | 14 +- .../browser/utils/templates/check_eventi.pt | 173 ++++++++++++++++ .../browser/utils/templates/utils.pt | 6 + 5 files changed, 384 insertions(+), 2 deletions(-) create mode 100644 src/design/plone/contenttypes/browser/utils/check_eventi.py create mode 100644 src/design/plone/contenttypes/browser/utils/templates/check_eventi.pt diff --git a/CHANGES.rst b/CHANGES.rst index ded58c60..0d91a842 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,8 @@ Changelog 6.1.2 (unreleased) ------------------ -- Nothing changed yet. +- Added utility views: @@check-eventi and @@download-check-eventi. + [daniele] 6.1.1 (2023-11-21) diff --git a/src/design/plone/contenttypes/browser/utils/check_eventi.py b/src/design/plone/contenttypes/browser/utils/check_eventi.py new file mode 100644 index 00000000..190c42a6 --- /dev/null +++ b/src/design/plone/contenttypes/browser/utils/check_eventi.py @@ -0,0 +1,190 @@ +from openpyxl import Workbook +from openpyxl.styles import Alignment +from openpyxl.styles import Font +from openpyxl.styles import PatternFill +from openpyxl.utils import get_column_letter +from plone import api +from Products.Five import BrowserView + +import io + + +FLAG = '' + + +class CheckEventi(BrowserView): + cds = None + + def is_anonymous(self): + return api.user.is_anonymous() + + def information_dict(self, evento): + prezzo = getattr(evento, "prezzo", "") + res = [x.get("text", "") for x in prezzo["blocks"].values()] + if not [x for x in res if x]: + prezzo = "" + + return { + "description": getattr(evento, "description", "").strip(), + "effective_date": getattr(evento, "effective_date", None), + "luoghi_correlati": getattr(evento, "luoghi_correlati", None), + "prezzo": prezzo, + "contact_info": getattr(evento, "contact_info", None), + } + + def plone2volto(self, url): + portal_url = api.portal.get().absolute_url() + frontend_domain = api.portal.get_registry_record( + "volto.frontend_domain", default="" + ) + if frontend_domain and url.startswith(portal_url): + return url.replace(portal_url, frontend_domain, 1) + return url + + def get_eventi(self): + if self.is_anonymous(): + return [] + pc = api.portal.get_tool("portal_catalog") + + query = { + "portal_type": "Event", + "review_state": "published", + } + brains = pc(query) + results = {} + for brain in brains: + evento = brain.getObject() + + information_dict = self.information_dict(evento) + if all(information_dict.values()): + continue + + parent = evento.aq_inner.aq_parent + if parent.title not in results: + results[parent.title] = { + "url": self.plone2volto(parent.absolute_url()), + "children": [], + } + results[parent.title]["children"].append( + { + "title": evento.title, + "description": information_dict.get("description") and FLAG or "", + "url": self.plone2volto(evento.absolute_url()), + "data": { + "effective_date": information_dict.get("effective_date") + and FLAG + or "", + "luoghi_correlati": information_dict.get("luoghi_correlati") + and FLAG + or "", + "prezzo": information_dict.get("prezzo") and FLAG or "", + "contact_info": information_dict.get("contact_info") + and FLAG + or "", + }, + } + ) + + results = dict(sorted(results.items())) + for key in results: + results[key]["children"].sort(key=lambda x: x["title"]) + + return results + + +class DownloadCheckEventi(CheckEventi): + CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + + def __call__(self): + HEADER = [ + "Titolo", + "Descrizione", + "Data", + "Luogo", + "Costo", + "Contatti", + ] + + EMPTY_ROW = [""] * 3 + + eventi = self.get_eventi() + + workbook = Workbook() + sheet = workbook.active + sheet.title = "Check Persone" + header_font = Font(bold=True) + section_link_font = Font(underline="single", color="0563C1", size=14) + link_fill = PatternFill(fill_type="solid", fgColor="DDDDDD") + link_font = Font(underline="single", color="0563C1") + section_fill = PatternFill(fill_type="solid", fgColor="E9E9E9") + alignment = Alignment(horizontal="center", vertical="top", wrapText=True) + + section_row_height = int(14 * 1.5) + + for category, category_data in eventi.items(): + section_url = category_data["url"] + section_title = category + section_row = [section_title, "", ""] + sheet.append(section_row) + section_cell = sheet.cell(row=sheet.max_row, column=1) + + section_cell.alignment = alignment + section_cell.hyperlink = section_url + sheet.merge_cells( + start_row=sheet.max_row, + start_column=1, + end_row=sheet.max_row, + end_column=3, + ) # noqa + for row in sheet.iter_rows( + min_row=sheet.max_row, max_row=sheet.max_row, min_col=1, max_col=3 + ): # noqa + sheet.row_dimensions[row[0].row].height = section_row_height + for cell in row: + cell.fill = section_fill + cell.font = section_link_font + + sheet.append(HEADER) + for col in range(1, len(HEADER) + 1): + header_cell = sheet.cell(row=sheet.max_row, column=col) + header_cell.fill = link_fill + header_cell.font = header_font + + for col in sheet.columns: + column_letter = get_column_letter(col[0].column) + sheet.column_dimensions[column_letter].width = 35 + + for evento in category_data["children"]: + title_url = evento["url"] + dati_evento = [ + evento["title"], + "X" if evento["description"] else "", + "X" if evento["data"]["effective_date"] else "", + "X" if evento["data"]["luoghi_correlati"] else "", + "X" if evento["data"]["prezzo"] else "", + "X" if evento["data"]["contact_info"] else "", + ] + row = dati_evento + sheet.append(row) + + title_cell = sheet.cell(row=sheet.max_row, column=1) + check_cell = sheet.cell(row=sheet.max_row, column=2) + check_cell.alignment = check_cell.alignment.copy(horizontal="center") + title_cell.hyperlink = title_url + title_cell.font = link_font + column_letter_unit = get_column_letter(title_cell.column) + sheet.column_dimensions[column_letter_unit].width = 60 + + sheet.append(EMPTY_ROW) + sheet.append(EMPTY_ROW) + + bytes_io = io.BytesIO() + workbook.save(bytes_io) + data = bytes_io.getvalue() + self.request.response.setHeader("Content-Length", len(data)) + self.request.RESPONSE.setHeader("Content-Type", self.CT) + self.request.response.setHeader( + "Content-Disposition", + "attachment; filename=check_eventi.xlsx", + ) + return data diff --git a/src/design/plone/contenttypes/browser/utils/configure.zcml b/src/design/plone/contenttypes/browser/utils/configure.zcml index 1421659b..f1c6fa85 100644 --- a/src/design/plone/contenttypes/browser/utils/configure.zcml +++ b/src/design/plone/contenttypes/browser/utils/configure.zcml @@ -41,7 +41,6 @@ template="templates/check_servizi.pt" permission="zope2.Public" /> - + + diff --git a/src/design/plone/contenttypes/browser/utils/templates/check_eventi.pt b/src/design/plone/contenttypes/browser/utils/templates/check_eventi.pt new file mode 100644 index 00000000..0f01a710 --- /dev/null +++ b/src/design/plone/contenttypes/browser/utils/templates/check_eventi.pt @@ -0,0 +1,173 @@ + + + + + + + + + + + + + +

Verifica dello stato degli Eventi

+
+ Non hai i permessi per vedere questo elenco di informazioni. Se pensi + che questo non sia corretto verifica di essere autenticato oppure rivolgiti + agli amministratori del sito. +
+ +
+

+ La lista seguente elenca tutti quegli Eventi per i quali non sono + ancora stati aggiunti i campi che AGID indica come obbligatori. + Ogni redattore può vedere in questa lista tutti gli Eventi e, + cliccando su ognuno, andare alla vista di dettaglio dell'Evento, + editarlo e compilare tutti i campi obbligatori.

+

Si fa notare, infine, che la seguente lista degli Eventi + presenta tutti quelli in stato pubblicato e + non scaduti + secondo + le logiche di pubblicazione del CMS Plone, ovvero con una data di scadenza ancora da raggiugnere.

+ +
+
+
+ + +
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/design/plone/contenttypes/browser/utils/templates/utils.pt b/src/design/plone/contenttypes/browser/utils/templates/utils.pt index 364313ca..12ecc6c5 100644 --- a/src/design/plone/contenttypes/browser/utils/templates/utils.pt +++ b/src/design/plone/contenttypes/browser/utils/templates/utils.pt @@ -39,6 +39,12 @@ Verifica dello stato dei servizi.

+
  • + Check eventi +

    + Verifica dello stato degli eventi. +

    +

  • From de4df094ed4adf305a168930ea997a104ee53c28 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Thu, 23 Nov 2023 15:10:47 +0100 Subject: [PATCH 2/4] zpretty --- .../plone/contenttypes/browser/utils/configure.zcml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/design/plone/contenttypes/browser/utils/configure.zcml b/src/design/plone/contenttypes/browser/utils/configure.zcml index 9668e294..5127dcf5 100644 --- a/src/design/plone/contenttypes/browser/utils/configure.zcml +++ b/src/design/plone/contenttypes/browser/utils/configure.zcml @@ -53,6 +53,12 @@ class=".check_persone.DownloadCheckPersone" permission="zope2.Public" /> + Date: Thu, 23 Nov 2023 15:11:31 +0100 Subject: [PATCH 3/4] ci: cache tox --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d7b0bd7b..0f5ee019 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -32,6 +32,7 @@ jobs: path: | ~/.cache/pip eggs + .tox key: ${{ runner.os }}-pip-${{ matrix.config[0] }}-${{ hashFiles('setup.*', 'tox.ini') }} restore-keys: | ${{ runner.os }}-pip-${{ matrix.config[0] }}- From 9d0828a2793900cff1756c3001282be06de0a032 Mon Sep 17 00:00:00 2001 From: Mauro Amico Date: Thu, 23 Nov 2023 18:15:35 +0100 Subject: [PATCH 4/4] Update src/design/plone/contenttypes/browser/utils/configure.zcml --- src/design/plone/contenttypes/browser/utils/configure.zcml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/design/plone/contenttypes/browser/utils/configure.zcml b/src/design/plone/contenttypes/browser/utils/configure.zcml index 5127dcf5..a76528f4 100644 --- a/src/design/plone/contenttypes/browser/utils/configure.zcml +++ b/src/design/plone/contenttypes/browser/utils/configure.zcml @@ -57,6 +57,7 @@ name="check-eventi" for="*" class=".check_eventi.CheckEventi" + permission="cmf.ManagePortal" template="templates/check_eventi.pt" />