Skip to content

Commit f754ca0

Browse files
Added utils view for UO
1 parent 9cf044d commit f754ca0

File tree

4 files changed

+394
-1
lines changed

4 files changed

+394
-1
lines changed

CHANGES.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ Changelog
44
6.1.1 (unreleased)
55
------------------
66

7-
- Nothing changed yet.
7+
- Added utils view for UO.
8+
[daniele]
89

910

1011
6.1.0 (2023-11-07)
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
from DateTime import DateTime
2+
from openpyxl import Workbook
3+
from openpyxl.styles import Alignment
4+
from openpyxl.styles import Font
5+
from openpyxl.styles import PatternFill
6+
from openpyxl.utils import get_column_letter
7+
from plone import api
8+
from Products.Five import BrowserView
9+
from zope.globalrequest import getRequest
10+
from zope.component import getMultiAdapter
11+
from plone.restapi.interfaces import ISerializeToJsonSummary
12+
13+
import io
14+
15+
16+
FLAG = '<i class="fa-solid fa-check"></i>'
17+
18+
19+
class CheckUnitaOrganizzative(BrowserView):
20+
cds = None
21+
22+
def is_anonymous(self):
23+
return api.user.is_anonymous()
24+
25+
def get_relations(self, obj, field):
26+
return api.relation.get(source=obj, relationship=field, unrestricted=False)
27+
28+
def get_related_objects(self, obj, field):
29+
""" """
30+
items = []
31+
relations = self.get_relations(obj, field)
32+
33+
for rel in relations:
34+
rel_obj = rel.to_object
35+
if rel_obj is not None:
36+
summary = getMultiAdapter(
37+
(rel_obj, getRequest()), ISerializeToJsonSummary
38+
)()
39+
items.append(summary)
40+
return sorted(items, key=lambda k: k["title"])
41+
42+
def information_dict(self, uo):
43+
sede_ref = None
44+
sede_ref = self.get_related_objects(uo, "sede")
45+
if sede_ref:
46+
sede_ref = sede_ref[0]
47+
48+
competenze = getattr(uo, "competenze", "")
49+
res = [x.get("text", "") for x in competenze["blocks"].values()]
50+
if not [x for x in res if x]:
51+
competenze = ""
52+
return {
53+
"description": getattr(uo, "description", "").strip(),
54+
"competenze": competenze,
55+
"sede": sede_ref,
56+
"contact_info": getattr(uo, "contact_info", None),
57+
}
58+
59+
def plone2volto(self, url):
60+
portal_url = api.portal.get().absolute_url()
61+
frontend_domain = api.portal.get_registry_record(
62+
"volto.frontend_domain", default=""
63+
)
64+
if frontend_domain and url.startswith(portal_url):
65+
return url.replace(portal_url, frontend_domain, 1)
66+
return url
67+
68+
def get_uos(self):
69+
70+
if self.is_anonymous():
71+
return []
72+
pc = api.portal.get_tool("portal_catalog")
73+
74+
# show_inactive ha sempre avuto una gestione... particolare! aggiungo ai
75+
# kw effectiveRange = DateTime() che è quello che fa Products.CMFPlone
76+
# nel CatalogTool.py
77+
query = {
78+
"portal_type": "UnitaOrganizzativa",
79+
"review_state": "published",
80+
}
81+
brains = pc(query, **{"effectiveRange": DateTime()})
82+
results = {}
83+
for brain in brains:
84+
uo = brain.getObject()
85+
86+
information_dict = self.information_dict(uo)
87+
88+
if all(information_dict.values()):
89+
continue
90+
91+
parent = uo.aq_inner.aq_parent
92+
if parent.title not in results:
93+
results[parent.title] = {
94+
"url": self.plone2volto(parent.absolute_url()),
95+
"children": [],
96+
}
97+
results[parent.title]["children"].append(
98+
{
99+
"title": uo.title,
100+
"description": information_dict.get("description") and FLAG or "",
101+
"url": self.plone2volto(uo.absolute_url()),
102+
"data": {
103+
"competenze": information_dict.get("competenze") and FLAG or "",
104+
"sede": information_dict.get("sede") and FLAG or "",
105+
"contact_info": information_dict.get("contact_info")
106+
and FLAG
107+
or "",
108+
},
109+
}
110+
)
111+
112+
results = dict(sorted(results.items()))
113+
for key in results:
114+
results[key]["children"].sort(key=lambda x: x["title"])
115+
116+
return results
117+
118+
119+
class DownloadCheckUnitaOrganizzative(CheckUnitaOrganizzative):
120+
CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
121+
122+
def __call__(self):
123+
HEADER = ["Titolo", "Descrizione", "Competenze", "Sede", "Contatti"]
124+
125+
EMPTY_ROW = [""] * 3
126+
127+
unita_organizzative = self.get_uos()
128+
129+
workbook = Workbook()
130+
sheet = workbook.active
131+
sheet.title = "Check Persone"
132+
header_font = Font(bold=True)
133+
section_link_font = Font(underline="single", color="0563C1", size=14)
134+
link_fill = PatternFill(fill_type="solid", fgColor="DDDDDD")
135+
link_font = Font(underline="single", color="0563C1")
136+
section_fill = PatternFill(fill_type="solid", fgColor="E9E9E9")
137+
alignment = Alignment(horizontal="center", vertical="top", wrapText=True)
138+
139+
section_row_height = int(14 * 1.5)
140+
141+
for category, category_data in unita_organizzative.items():
142+
section_url = category_data["url"]
143+
section_title = category
144+
section_row = [section_title, "", ""]
145+
sheet.append(section_row)
146+
section_cell = sheet.cell(row=sheet.max_row, column=1)
147+
148+
section_cell.alignment = alignment
149+
section_cell.hyperlink = section_url
150+
sheet.merge_cells(
151+
start_row=sheet.max_row,
152+
start_column=1,
153+
end_row=sheet.max_row,
154+
end_column=3,
155+
) # noqa
156+
for row in sheet.iter_rows(
157+
min_row=sheet.max_row, max_row=sheet.max_row, min_col=1, max_col=3
158+
): # noqa
159+
sheet.row_dimensions[row[0].row].height = section_row_height
160+
for cell in row:
161+
cell.fill = section_fill
162+
cell.font = section_link_font
163+
164+
sheet.append(HEADER)
165+
for col in range(1, len(HEADER) + 1):
166+
header_cell = sheet.cell(row=sheet.max_row, column=col)
167+
header_cell.fill = link_fill
168+
header_cell.font = header_font
169+
170+
for col in sheet.columns:
171+
column_letter = get_column_letter(col[0].column)
172+
sheet.column_dimensions[column_letter].width = 35
173+
174+
for uo in category_data["children"]:
175+
title_url = uo["url"]
176+
dati_uo = [
177+
uo["title"],
178+
"X" if uo["description"] else "",
179+
"X" if uo["data"]["competenze"] else "",
180+
"X" if uo["data"]["sede"] else "",
181+
"X" if uo["data"]["contact_info"] else "",
182+
]
183+
row = dati_uo
184+
sheet.append(row)
185+
186+
title_cell = sheet.cell(row=sheet.max_row, column=1)
187+
check_cell = sheet.cell(row=sheet.max_row, column=2)
188+
check_cell.alignment = check_cell.alignment.copy(horizontal="center")
189+
title_cell.hyperlink = title_url
190+
title_cell.font = link_font
191+
column_letter_unit = get_column_letter(title_cell.column)
192+
sheet.column_dimensions[column_letter_unit].width = 60
193+
194+
sheet.append(EMPTY_ROW)
195+
sheet.append(EMPTY_ROW)
196+
197+
bytes_io = io.BytesIO()
198+
workbook.save(bytes_io)
199+
data = bytes_io.getvalue()
200+
self.request.response.setHeader("Content-Length", len(data))
201+
self.request.RESPONSE.setHeader("Content-Type", self.CT)
202+
self.request.response.setHeader(
203+
"Content-Disposition",
204+
"attachment; filename=check_unita_organizzative.xlsx",
205+
)
206+
return data

src/design/plone/contenttypes/browser/utils/configure.zcml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,20 @@
5454
class=".check_persone.DownloadCheckPersone"
5555
permission="zope2.Public"
5656
/>
57+
58+
<browser:page
59+
name="check-uo"
60+
for="*"
61+
class=".check_uo.CheckUnitaOrganizzative"
62+
template="templates/check_uo.pt"
63+
permission="cmf.ManagePortal"
64+
/>
65+
66+
<browser:page
67+
name="download-check-uo"
68+
for="*"
69+
class=".check_uo.DownloadCheckUnitaOrganizzative"
70+
permission="cmf.ManagePortal"
71+
/>
5772

5873
</configure>

0 commit comments

Comments
 (0)