rer.linkmap 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rer/linkmap/__init__.py +13 -0
- rer/linkmap/browser/__init__.py +0 -0
- rer/linkmap/browser/configure.zcml +21 -0
- rer/linkmap/browser/views.py +109 -0
- rer/linkmap/configure.zcml +28 -0
- rer/linkmap/content/__init__.py +0 -0
- rer/linkmap/controlpanels/__init__.py +0 -0
- rer/linkmap/controlpanels/configure.zcml +14 -0
- rer/linkmap/controlpanels/settings.py +189 -0
- rer/linkmap/dependencies.zcml +7 -0
- rer/linkmap/indexers/__init__.py +0 -0
- rer/linkmap/indexers/configure.zcml +7 -0
- rer/linkmap/interfaces.py +7 -0
- rer/linkmap/linkmap.py +143 -0
- rer/linkmap/locales/__init__.py +0 -0
- rer/linkmap/locales/__main__.py +69 -0
- rer/linkmap/locales/en/LC_MESSAGES/redturtle.linkmap.po +45 -0
- rer/linkmap/locales/it/LC_MESSAGES/redturtle.linkmap.po +468 -0
- rer/linkmap/locales/redturtle.linkmap.pot +471 -0
- rer/linkmap/permissions.zcml +5 -0
- rer/linkmap/profiles/default/browserlayer.xml +6 -0
- rer/linkmap/profiles/default/catalog.xml +13 -0
- rer/linkmap/profiles/default/controlpanel.xml +20 -0
- rer/linkmap/profiles/default/diff_tool.xml +6 -0
- rer/linkmap/profiles/default/metadata.xml +7 -0
- rer/linkmap/profiles/default/registry/main.xml +8 -0
- rer/linkmap/profiles/default/repositorytool.xml +6 -0
- rer/linkmap/profiles/default/rolemap.xml +6 -0
- rer/linkmap/profiles/default/types/.gitkeep +0 -0
- rer/linkmap/profiles/default/types.xml +10 -0
- rer/linkmap/profiles/uninstall/browserlayer.xml +6 -0
- rer/linkmap/profiles.zcml +32 -0
- rer/linkmap/restapi/__init__.py +0 -0
- rer/linkmap/restapi/configure.zcml +8 -0
- rer/linkmap/restapi/services/__init__.py +0 -0
- rer/linkmap/restapi/services/configure.zcml +13 -0
- rer/linkmap/restapi/services/controlpanel.py +19 -0
- rer/linkmap/serializers/__init__.py +0 -0
- rer/linkmap/serializers/configure.zcml +10 -0
- rer/linkmap/serializers/summary.py +10 -0
- rer/linkmap/setuphandlers/__init__.py +17 -0
- rer/linkmap/testing.py +49 -0
- rer/linkmap/upgrades/__init__.py +0 -0
- rer/linkmap/upgrades/configure.zcml +21 -0
- rer/linkmap/vocabularies/__init__.py +0 -0
- rer/linkmap/vocabularies/configure.zcml +5 -0
- rer_linkmap-1.0.1.dist-info/METADATA +61 -0
- rer_linkmap-1.0.1.dist-info/RECORD +52 -0
- rer_linkmap-1.0.1.dist-info/WHEEL +4 -0
- rer_linkmap-1.0.1.dist-info/entry_points.txt +2 -0
- rer_linkmap-1.0.1.dist-info/licenses/LICENSE.GPL +339 -0
- rer_linkmap-1.0.1.dist-info/licenses/LICENSE.md +15 -0
rer/linkmap/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<configure
|
|
2
|
+
xmlns="http://namespaces.zope.org/zope"
|
|
3
|
+
xmlns:browser="http://namespaces.zope.org/browser"
|
|
4
|
+
i18n_domain="rer.linkmap"
|
|
5
|
+
>
|
|
6
|
+
|
|
7
|
+
<browser:page
|
|
8
|
+
name="at_map.json"
|
|
9
|
+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
|
|
10
|
+
class=".views.ATMapJSONView"
|
|
11
|
+
permission="zope2.View"
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
<browser:page
|
|
15
|
+
name="at_map.xml"
|
|
16
|
+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
|
|
17
|
+
class=".views.ATMapXMLView"
|
|
18
|
+
permission="zope2.View"
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
</configure>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from Acquisition import aq_base
|
|
2
|
+
from json import dumps
|
|
3
|
+
from plone import api
|
|
4
|
+
from Products.Five import BrowserView
|
|
5
|
+
from rer.linkmap.linkmap import CATEGORY_C1
|
|
6
|
+
from rer.linkmap.linkmap import CATEGORY_KEYS
|
|
7
|
+
from rer.linkmap.linkmap import ensure_required_root_url
|
|
8
|
+
from rer.linkmap.linkmap import is_valid_date
|
|
9
|
+
from rer.linkmap.linkmap import is_valid_url
|
|
10
|
+
from rer.linkmap.linkmap import today_date_string
|
|
11
|
+
from xml.sax.saxutils import escape
|
|
12
|
+
from zExceptions import NotFound
|
|
13
|
+
|
|
14
|
+
REGISTRY_PREFIX = "rer.linkmap.controlpanels.settings.ILinkMapSettings"
|
|
15
|
+
ROOT_KEY = "amministrazione_trasparente"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_registry_value(field_name, default=""):
|
|
19
|
+
return api.portal.get_registry_record(
|
|
20
|
+
f"{REGISTRY_PREFIX}.{field_name}",
|
|
21
|
+
default=default,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_expose_json():
|
|
26
|
+
return get_registry_value("expose_json", default=True)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_expose_xml():
|
|
30
|
+
return get_registry_value("expose_xml", default=True)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_data_ultima_modifica():
|
|
34
|
+
value = get_registry_value("data_ultima_modifica")
|
|
35
|
+
if is_valid_date(value):
|
|
36
|
+
return value
|
|
37
|
+
return today_date_string()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def build_category_map_from_fields():
|
|
41
|
+
"""Build category map from individual field values."""
|
|
42
|
+
category_map = {}
|
|
43
|
+
for key in CATEGORY_KEYS:
|
|
44
|
+
value = get_registry_value(key)
|
|
45
|
+
if value and is_valid_url(value.strip()):
|
|
46
|
+
category_map[key] = value.strip()
|
|
47
|
+
return category_map
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def build_payload():
|
|
51
|
+
data_ultima_modifica = get_data_ultima_modifica()
|
|
52
|
+
category_map = build_category_map_from_fields()
|
|
53
|
+
ensure_required_root_url(category_map, api.portal.get().absolute_url())
|
|
54
|
+
|
|
55
|
+
payload = {
|
|
56
|
+
"data_ultima_modifica": data_ultima_modifica,
|
|
57
|
+
CATEGORY_C1: category_map,
|
|
58
|
+
}
|
|
59
|
+
return payload
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def build_xml(payload):
|
|
63
|
+
root_open = '<amministrazione_trasparente xmlns="https://guida-servizi.anticorruzione.it/trasparenza">'
|
|
64
|
+
lines = [
|
|
65
|
+
'<?xml version="1.0" encoding="utf-8"?>',
|
|
66
|
+
root_open,
|
|
67
|
+
f" <data_ultima_modifica>{escape(payload['data_ultima_modifica'])}"
|
|
68
|
+
"</data_ultima_modifica>",
|
|
69
|
+
" <map>",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
category = CATEGORY_C1
|
|
73
|
+
|
|
74
|
+
lines.append(f" <{category}>")
|
|
75
|
+
map_values = payload.get(category, {})
|
|
76
|
+
for map_key in CATEGORY_KEYS:
|
|
77
|
+
map_url = map_values.get(map_key)
|
|
78
|
+
if not map_url:
|
|
79
|
+
continue
|
|
80
|
+
lines.append(f" <{map_key}>{escape(map_url)}</{map_key}>")
|
|
81
|
+
lines.append(f" </{category}>")
|
|
82
|
+
lines.extend([" </map>", "</amministrazione_trasparente>"])
|
|
83
|
+
return "\n".join(lines)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class ATMapJSONView(BrowserView):
|
|
87
|
+
def __call__(self):
|
|
88
|
+
if aq_base(self.context) is not aq_base(api.portal.get()):
|
|
89
|
+
raise NotFound()
|
|
90
|
+
if not get_expose_json():
|
|
91
|
+
raise NotFound("JSON view is not enabled")
|
|
92
|
+
self.request.response.setHeader(
|
|
93
|
+
"Content-Type", "application/json; charset=utf-8"
|
|
94
|
+
)
|
|
95
|
+
payload = build_payload()
|
|
96
|
+
return dumps(payload, indent=2, ensure_ascii=False, sort_keys=True)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class ATMapXMLView(BrowserView):
|
|
100
|
+
def __call__(self):
|
|
101
|
+
if aq_base(self.context) is not aq_base(api.portal.get()):
|
|
102
|
+
raise NotFound()
|
|
103
|
+
if not get_expose_xml():
|
|
104
|
+
raise NotFound("XML view is not enabled")
|
|
105
|
+
self.request.response.setHeader(
|
|
106
|
+
"Content-Type", "application/xml; charset=utf-8"
|
|
107
|
+
)
|
|
108
|
+
payload = build_payload()
|
|
109
|
+
return build_xml(payload)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<configure
|
|
2
|
+
xmlns="http://namespaces.zope.org/zope"
|
|
3
|
+
xmlns:i18n="http://namespaces.zope.org/i18n"
|
|
4
|
+
i18n_domain="rer.linkmap"
|
|
5
|
+
>
|
|
6
|
+
|
|
7
|
+
<i18n:registerTranslations directory="locales" />
|
|
8
|
+
|
|
9
|
+
<include
|
|
10
|
+
package="Products.CMFCore"
|
|
11
|
+
file="permissions.zcml"
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
<include file="dependencies.zcml" />
|
|
16
|
+
<include file="profiles.zcml" />
|
|
17
|
+
<include file="permissions.zcml" />
|
|
18
|
+
|
|
19
|
+
<include package=".browser" />
|
|
20
|
+
<include package=".controlpanels" />
|
|
21
|
+
<include package=".indexers" />
|
|
22
|
+
<include package=".restapi" />
|
|
23
|
+
<include package=".serializers" />
|
|
24
|
+
<include package=".vocabularies" />
|
|
25
|
+
|
|
26
|
+
<!-- -*- extra stuff goes here -*- -->
|
|
27
|
+
|
|
28
|
+
</configure>
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<configure
|
|
2
|
+
xmlns="http://namespaces.zope.org/zope"
|
|
3
|
+
xmlns:browser="http://namespaces.zope.org/browser"
|
|
4
|
+
i18n_domain="rer.linkmap"
|
|
5
|
+
>
|
|
6
|
+
|
|
7
|
+
<browser:page
|
|
8
|
+
name="linkmap-settings"
|
|
9
|
+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
|
|
10
|
+
class=".settings.LinkMapControlPanelView"
|
|
11
|
+
permission="cmf.ManagePortal"
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
</configure>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
from plone.app.registry.browser.controlpanel import ControlPanelFormWrapper
|
|
2
|
+
from plone.app.registry.browser.controlpanel import RegistryEditForm
|
|
3
|
+
from rer.linkmap import _
|
|
4
|
+
from rer.linkmap.linkmap import is_valid_date
|
|
5
|
+
from zope.interface import Interface
|
|
6
|
+
from zope.interface import invariant
|
|
7
|
+
from zope.interface import Invalid
|
|
8
|
+
from zope.schema import Bool
|
|
9
|
+
from zope.schema import TextLine
|
|
10
|
+
from zope.schema import URI
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _category_field(key):
|
|
14
|
+
return URI(
|
|
15
|
+
title=_(
|
|
16
|
+
f"{key}_title",
|
|
17
|
+
default=key.replace("_", " ").title(),
|
|
18
|
+
),
|
|
19
|
+
description=_(
|
|
20
|
+
f"{key}_description",
|
|
21
|
+
default="Inserisci l'url per questo dato",
|
|
22
|
+
),
|
|
23
|
+
required=False,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ILinkMapSettings(Interface):
|
|
28
|
+
expose_json = Bool(
|
|
29
|
+
title=_("expose_json_title", default="Esponi vista JSON"),
|
|
30
|
+
description=_(
|
|
31
|
+
"expose_json_description",
|
|
32
|
+
default="Se selezionato, la mappa dei link sarà disponibile nel "
|
|
33
|
+
"formato JSON.",
|
|
34
|
+
),
|
|
35
|
+
required=False,
|
|
36
|
+
default=True,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
expose_xml = Bool(
|
|
40
|
+
title=_("expose_xml_title", default="Esponi vista XML"),
|
|
41
|
+
description=_(
|
|
42
|
+
"expose_xml_description",
|
|
43
|
+
default="Se selezionato, la mappa dei link sarà disponibile nel "
|
|
44
|
+
"formato XML.",
|
|
45
|
+
),
|
|
46
|
+
required=False,
|
|
47
|
+
default=True,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
data_ultima_modifica = TextLine(
|
|
51
|
+
title=_("data_ultima_modifica_title", default="Data ultima modifica"),
|
|
52
|
+
description=_(
|
|
53
|
+
"data_ultima_modifica_description",
|
|
54
|
+
default="Data in formato GG/MM/AAAA. Se non impostata verra usata "
|
|
55
|
+
"la data corrente.",
|
|
56
|
+
),
|
|
57
|
+
required=False,
|
|
58
|
+
default="",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
amministrazione_trasparente = _category_field("amministrazione_trasparente")
|
|
62
|
+
disposizioni_generali = _category_field("disposizioni_generali")
|
|
63
|
+
consulenti_collaboratori = _category_field("consulenti_collaboratori")
|
|
64
|
+
bandi_di_concorso = _category_field("bandi_di_concorso")
|
|
65
|
+
enti_controllati = _category_field("enti_controllati")
|
|
66
|
+
sovvenzioni = _category_field("sovvenzioni")
|
|
67
|
+
beni_immobili = _category_field("beni_immobili")
|
|
68
|
+
opere_pubbliche = _category_field("opere_pubbliche")
|
|
69
|
+
organizzazione = _category_field("organizzazione")
|
|
70
|
+
personale = _category_field("personale")
|
|
71
|
+
performance = _category_field("performance")
|
|
72
|
+
attivita_e_procedimenti = _category_field("attivita_e_procedimenti")
|
|
73
|
+
bandi_gara_e_contratti = _category_field("bandi_gara_e_contratti")
|
|
74
|
+
bilanci = _category_field("bilanci")
|
|
75
|
+
controlli_e_rilievi = _category_field("controlli_e_rilievi")
|
|
76
|
+
pagamenti = _category_field("pagamenti")
|
|
77
|
+
altri_contenuti = _category_field("altri_contenuti")
|
|
78
|
+
provvedimenti = _category_field("provvedimenti")
|
|
79
|
+
servizi_erogati = _category_field("servizi_erogati")
|
|
80
|
+
informazioni_ambientali = _category_field("informazioni_ambientali")
|
|
81
|
+
interventi_straordinari = _category_field("interventi_straordinari")
|
|
82
|
+
pianificazione_governo_territorio = _category_field(
|
|
83
|
+
"pianificazione_governo_territorio"
|
|
84
|
+
)
|
|
85
|
+
strutture_sanitarie_accreditate = _category_field("strutture_sanitarie_accreditate")
|
|
86
|
+
atti_generali = _category_field("atti_generali")
|
|
87
|
+
rischi_corruttivi_e_trasparenza = _category_field("rischi_corruttivi_e_trasparenza")
|
|
88
|
+
piano_integrato_attivita_organizzazione = _category_field(
|
|
89
|
+
"piano_integrato_attivita_organizzazione"
|
|
90
|
+
)
|
|
91
|
+
piano_triennale_prevenzione_corruzione_e_trasparenza = _category_field(
|
|
92
|
+
"piano_triennale_prevenzione_corruzione_e_trasparenza"
|
|
93
|
+
)
|
|
94
|
+
titolari_incarichi_collaborazione_consulenza = _category_field(
|
|
95
|
+
"titolari_incarichi_collaborazione_consulenza"
|
|
96
|
+
)
|
|
97
|
+
enti_diritto_privato_controllati = _category_field(
|
|
98
|
+
"enti_diritto_privato_controllati"
|
|
99
|
+
)
|
|
100
|
+
rappresentazione_grafica = _category_field("rappresentazione_grafica")
|
|
101
|
+
societa_partecipate = _category_field("societa_partecipate")
|
|
102
|
+
criteri_e_modalita = _category_field("criteri_e_modalita")
|
|
103
|
+
atti_di_concessione = _category_field("atti_di_concessione")
|
|
104
|
+
patrimonio_immobiliare = _category_field("patrimonio_immobiliare")
|
|
105
|
+
canoni_locazione_o_affitto = _category_field("canoni_locazione_o_affitto")
|
|
106
|
+
tempi_costi_opere_pubbliche = _category_field("tempi_costi_opere_pubbliche")
|
|
107
|
+
atti_programmazione_opere_pubbliche = _category_field(
|
|
108
|
+
"atti_programmazione_opere_pubbliche"
|
|
109
|
+
)
|
|
110
|
+
organi_di_indirizzo_politico_amministativo = _category_field(
|
|
111
|
+
"organi_di_indirizzo_politico_amministativo"
|
|
112
|
+
)
|
|
113
|
+
telefono_e_posta_elettronica = _category_field("telefono_e_posta_elettronica")
|
|
114
|
+
sanzioni_mancata_comunicazione_dati = _category_field(
|
|
115
|
+
"sanzioni_mancata_comunicazione_dati"
|
|
116
|
+
)
|
|
117
|
+
articolazione_uffici = _category_field("articolazione_uffici")
|
|
118
|
+
incarichi_amministrativi_di_vertice = _category_field(
|
|
119
|
+
"incarichi_amministrativi_di_vertice"
|
|
120
|
+
)
|
|
121
|
+
dirigenti_cessati = _category_field("dirigenti_cessati")
|
|
122
|
+
incarichi_conferiti_e_autorizzati_ai_dipendenti = _category_field(
|
|
123
|
+
"incarichi_conferiti_e_autorizzati_ai_dipendenti"
|
|
124
|
+
)
|
|
125
|
+
contrattazione_integrativa = _category_field("contrattazione_integrativa")
|
|
126
|
+
titolari_incarichi_dirigenziali_non_generali = _category_field(
|
|
127
|
+
"titolari_incarichi_dirigenziali_non_generali"
|
|
128
|
+
)
|
|
129
|
+
dotazione_organica = _category_field("dotazione_organica")
|
|
130
|
+
tassi_di_assenza = _category_field("tassi_di_assenza")
|
|
131
|
+
contrattazione_collettiva = _category_field("contrattazione_collettiva")
|
|
132
|
+
ammontare_complessivo_dei_premi = _category_field("ammontare_complessivo_dei_premi")
|
|
133
|
+
dati_relativi_ai_premi = _category_field("dati_relativi_ai_premi")
|
|
134
|
+
tipologie_di_procedimento = _category_field("tipologie_di_procedimento")
|
|
135
|
+
bilancio_preventivo_e_consuntivo = _category_field(
|
|
136
|
+
"bilancio_preventivo_e_consuntivo"
|
|
137
|
+
)
|
|
138
|
+
budget = _category_field("budget")
|
|
139
|
+
nuclei_di_valutazione = _category_field("nuclei_di_valutazione")
|
|
140
|
+
corte_dei_conti = _category_field("corte_dei_conti")
|
|
141
|
+
organi_revisione_amministrativa_e_contabile = _category_field(
|
|
142
|
+
"organi_revisione_amministrativa_e_contabile"
|
|
143
|
+
)
|
|
144
|
+
dati_sui_pagamenti = _category_field("dati_sui_pagamenti")
|
|
145
|
+
tempestivita_dei_pagamenti = _category_field("tempestivita_dei_pagamenti")
|
|
146
|
+
IBAN_e_pagamenti_informatici = _category_field("IBAN_e_pagamenti_informatici")
|
|
147
|
+
prevenzione_della_corruzione = _category_field("prevenzione_della_corruzione")
|
|
148
|
+
accessibilita_e_catalogo_dati = _category_field("accessibilita_e_catalogo_dati")
|
|
149
|
+
accesso_civico = _category_field("accesso_civico")
|
|
150
|
+
dati_ulteriori = _category_field("dati_ulteriori")
|
|
151
|
+
provvedimenti_organo_indirizzo_politico = _category_field(
|
|
152
|
+
"provvedimenti_organo_indirizzo_politico"
|
|
153
|
+
)
|
|
154
|
+
provvedimenti_dirigenti_amministrativi = _category_field(
|
|
155
|
+
"provvedimenti_dirigenti_amministrativi"
|
|
156
|
+
)
|
|
157
|
+
servizi_e_standard_di_qualita = _category_field("servizi_e_standard_di_qualita")
|
|
158
|
+
costi_contabilizzati = _category_field("costi_contabilizzati")
|
|
159
|
+
servizi_in_rete = _category_field("servizi_in_rete")
|
|
160
|
+
class_action = _category_field("class_action")
|
|
161
|
+
liste_di_attesa = _category_field("liste_di_attesa")
|
|
162
|
+
|
|
163
|
+
@invariant
|
|
164
|
+
def validate_map(data):
|
|
165
|
+
"""Validate the control panel settings."""
|
|
166
|
+
value = data.data_ultima_modifica or ""
|
|
167
|
+
if value and not is_valid_date(value):
|
|
168
|
+
raise Invalid(
|
|
169
|
+
_(
|
|
170
|
+
"invalid_date",
|
|
171
|
+
default="La data deve essere nel formato GG/MM/AAAA.",
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class LinkMapControlPanelForm(RegistryEditForm):
|
|
177
|
+
schema = ILinkMapSettings
|
|
178
|
+
id = "redturtle-linkmap-settings"
|
|
179
|
+
label = _(
|
|
180
|
+
"linkmap_controlpanel_title",
|
|
181
|
+
default="Configurazione at_map",
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class LinkMapControlPanelView(ControlPanelFormWrapper):
|
|
186
|
+
form = LinkMapControlPanelForm
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
__all__ = ["ILinkMapSettings", "LinkMapControlPanelForm", "LinkMapControlPanelView"]
|
|
File without changes
|
rer/linkmap/linkmap.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from zope.schema import URI
|
|
5
|
+
from zope.schema.interfaces import InvalidURI
|
|
6
|
+
|
|
7
|
+
CATEGORY_C1 = "at_art2_bis_c1"
|
|
8
|
+
ROOT_KEY = "amministrazione_trasparente"
|
|
9
|
+
|
|
10
|
+
CATEGORY_KEYS = (
|
|
11
|
+
"amministrazione_trasparente",
|
|
12
|
+
"disposizioni_generali",
|
|
13
|
+
"consulenti_collaboratori",
|
|
14
|
+
"bandi_di_concorso",
|
|
15
|
+
"enti_controllati",
|
|
16
|
+
"sovvenzioni",
|
|
17
|
+
"beni_immobili",
|
|
18
|
+
"opere_pubbliche",
|
|
19
|
+
"organizzazione",
|
|
20
|
+
"personale",
|
|
21
|
+
"performance",
|
|
22
|
+
"attivita_e_procedimenti",
|
|
23
|
+
"bandi_gara_e_contratti",
|
|
24
|
+
"bilanci",
|
|
25
|
+
"controlli_e_rilievi",
|
|
26
|
+
"pagamenti",
|
|
27
|
+
"altri_contenuti",
|
|
28
|
+
"provvedimenti",
|
|
29
|
+
"servizi_erogati",
|
|
30
|
+
"informazioni_ambientali",
|
|
31
|
+
"interventi_straordinari",
|
|
32
|
+
"pianificazione_governo_territorio",
|
|
33
|
+
"strutture_sanitarie_accreditate",
|
|
34
|
+
"atti_generali",
|
|
35
|
+
"rischi_corruttivi_e_trasparenza",
|
|
36
|
+
"piano_integrato_attivita_organizzazione",
|
|
37
|
+
"piano_triennale_prevenzione_corruzione_e_trasparenza",
|
|
38
|
+
"titolari_incarichi_collaborazione_consulenza",
|
|
39
|
+
"enti_diritto_privato_controllati",
|
|
40
|
+
"rappresentazione_grafica",
|
|
41
|
+
"societa_partecipate",
|
|
42
|
+
"criteri_e_modalita",
|
|
43
|
+
"atti_di_concessione",
|
|
44
|
+
"patrimonio_immobiliare",
|
|
45
|
+
"canoni_locazione_o_affitto",
|
|
46
|
+
"tempi_costi_opere_pubbliche",
|
|
47
|
+
"atti_programmazione_opere_pubbliche",
|
|
48
|
+
"organi_di_indirizzo_politico_amministativo",
|
|
49
|
+
"telefono_e_posta_elettronica",
|
|
50
|
+
"sanzioni_mancata_comunicazione_dati",
|
|
51
|
+
"articolazione_uffici",
|
|
52
|
+
"incarichi_amministrativi_di_vertice",
|
|
53
|
+
"dirigenti_cessati",
|
|
54
|
+
"incarichi_conferiti_e_autorizzati_ai_dipendenti",
|
|
55
|
+
"contrattazione_integrativa",
|
|
56
|
+
"titolari_incarichi_dirigenziali_non_generali",
|
|
57
|
+
"dotazione_organica",
|
|
58
|
+
"tassi_di_assenza",
|
|
59
|
+
"contrattazione_collettiva",
|
|
60
|
+
"ammontare_complessivo_dei_premi",
|
|
61
|
+
"dati_relativi_ai_premi",
|
|
62
|
+
"tipologie_di_procedimento",
|
|
63
|
+
"bilancio_preventivo_e_consuntivo",
|
|
64
|
+
"budget",
|
|
65
|
+
"nuclei_di_valutazione",
|
|
66
|
+
"corte_dei_conti",
|
|
67
|
+
"organi_revisione_amministrativa_e_contabile",
|
|
68
|
+
"dati_sui_pagamenti",
|
|
69
|
+
"tempestivita_dei_pagamenti",
|
|
70
|
+
"IBAN_e_pagamenti_informatici",
|
|
71
|
+
"prevenzione_della_corruzione",
|
|
72
|
+
"accessibilita_e_catalogo_dati",
|
|
73
|
+
"accesso_civico",
|
|
74
|
+
"dati_ulteriori",
|
|
75
|
+
"provvedimenti_organo_indirizzo_politico",
|
|
76
|
+
"provvedimenti_dirigenti_amministrativi",
|
|
77
|
+
"servizi_e_standard_di_qualita",
|
|
78
|
+
"costi_contabilizzati",
|
|
79
|
+
"servizi_in_rete",
|
|
80
|
+
"class_action",
|
|
81
|
+
"liste_di_attesa",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
DATE_RE = re.compile(r"^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/([2]\d{3})$")
|
|
85
|
+
URL_FIELD = URI(required=False)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def is_valid_date(value):
|
|
89
|
+
return bool(value and DATE_RE.fullmatch(value))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def today_date_string():
|
|
93
|
+
return date.today().strftime("%d/%m/%Y")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def is_valid_url(value):
|
|
97
|
+
if not value:
|
|
98
|
+
return False
|
|
99
|
+
try:
|
|
100
|
+
URL_FIELD.validate(value.strip())
|
|
101
|
+
except InvalidURI:
|
|
102
|
+
return False
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def allowed_keys():
|
|
107
|
+
return set(CATEGORY_KEYS)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def parse_entries(raw_value):
|
|
111
|
+
lines = (raw_value or "").splitlines()
|
|
112
|
+
pairs = []
|
|
113
|
+
for line in lines:
|
|
114
|
+
cleaned = line.strip()
|
|
115
|
+
if not cleaned:
|
|
116
|
+
continue
|
|
117
|
+
if "|" not in cleaned:
|
|
118
|
+
raise ValueError(f"Invalid line format: {cleaned}")
|
|
119
|
+
key, url = cleaned.split("|", 1)
|
|
120
|
+
key = key.strip()
|
|
121
|
+
url = url.strip()
|
|
122
|
+
if not key or not url:
|
|
123
|
+
raise ValueError(f"Invalid line format: {cleaned}")
|
|
124
|
+
pairs.append((key, url))
|
|
125
|
+
return pairs
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def build_category_map(raw_entries):
|
|
129
|
+
key_values = {}
|
|
130
|
+
allowed = allowed_keys()
|
|
131
|
+
for key, url in parse_entries(raw_entries):
|
|
132
|
+
if key not in allowed:
|
|
133
|
+
continue
|
|
134
|
+
if not is_valid_url(url):
|
|
135
|
+
continue
|
|
136
|
+
key_values[key] = url
|
|
137
|
+
return key_values
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def ensure_required_root_url(category_map, fallback_url):
|
|
141
|
+
if category_map.get(ROOT_KEY):
|
|
142
|
+
return
|
|
143
|
+
category_map[ROOT_KEY] = fallback_url
|
|
File without changes
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Update locales."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import re
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger("i18n")
|
|
11
|
+
logger.setLevel(logging.DEBUG)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
PATTERN = r"^[a-z]{2}.*"
|
|
15
|
+
|
|
16
|
+
locale_path = Path(__file__).parent.resolve()
|
|
17
|
+
target_path = locale_path.parent.resolve()
|
|
18
|
+
domains = [path.name[:-4] for path in locale_path.glob("*.pot")]
|
|
19
|
+
|
|
20
|
+
i18ndude = "uvx i18ndude"
|
|
21
|
+
|
|
22
|
+
# ignore node_modules files resulting in errors
|
|
23
|
+
excludes = '"*.html *json-schema*.xml"'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def locale_folder_setup(domain: str):
|
|
27
|
+
languages = [path for path in locale_path.glob("*") if path.is_dir()]
|
|
28
|
+
for lang_folder in languages:
|
|
29
|
+
lc_messages_path = lang_folder / "LC_MESSAGES"
|
|
30
|
+
lang = lang_folder.name
|
|
31
|
+
if lc_messages_path.exists():
|
|
32
|
+
continue
|
|
33
|
+
elif re.match(PATTERN, lang):
|
|
34
|
+
lc_messages_path.mkdir()
|
|
35
|
+
cmd = (
|
|
36
|
+
f"msginit --locale={lang} "
|
|
37
|
+
f"--input={locale_path}/{domain}.pot "
|
|
38
|
+
f"--output={locale_path}/{lang}/LC_MESSAGES/{domain}.po"
|
|
39
|
+
)
|
|
40
|
+
subprocess.call(cmd, shell=True) # noQA: S602
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _rebuild(domain: str):
|
|
44
|
+
cmd = (
|
|
45
|
+
f"{i18ndude} rebuild-pot --pot {locale_path}/{domain}.pot "
|
|
46
|
+
f"--exclude {excludes} "
|
|
47
|
+
f"--create {domain} {target_path}"
|
|
48
|
+
)
|
|
49
|
+
subprocess.call(cmd, shell=True) # noQA: S602
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _sync(domain: str):
|
|
53
|
+
cmd = (
|
|
54
|
+
f"{i18ndude} sync --pot {locale_path}/{domain}.pot "
|
|
55
|
+
f"{locale_path}/*/LC_MESSAGES/{domain}.po"
|
|
56
|
+
)
|
|
57
|
+
subprocess.call(cmd, shell=True) # noQA: S602
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def main():
|
|
61
|
+
for domain in domains:
|
|
62
|
+
logger.info(f"Updating translations for {domain}")
|
|
63
|
+
locale_folder_setup(domain)
|
|
64
|
+
_rebuild(domain)
|
|
65
|
+
_sync(domain)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
main()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
msgid ""
|
|
2
|
+
msgstr ""
|
|
3
|
+
"Project-Id-Version: PACKAGE VERSION\n"
|
|
4
|
+
"POT-Creation-Date: 2022-05-25 17:12+0000\n"
|
|
5
|
+
"PO-Revision-Date: YEAR-MO-DA HO:MI +ZONE\n"
|
|
6
|
+
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
|
7
|
+
"Language-Team: LANGUAGE <LL@li.org>\n"
|
|
8
|
+
"MIME-Version: 1.0\n"
|
|
9
|
+
"Content-Type: text/plain; charset=utf-8\n"
|
|
10
|
+
"Content-Transfer-Encoding: 8bit\n"
|
|
11
|
+
"Plural-Forms: nplurals=1; plural=0\n"
|
|
12
|
+
"Language-Code: en\n"
|
|
13
|
+
"Language-Name: English\n"
|
|
14
|
+
"Preferred-Encodings: utf-8 latin1\n"
|
|
15
|
+
"Domain: rer.linkmap\n"
|
|
16
|
+
|
|
17
|
+
msgid "data_ultima_modifica_title"
|
|
18
|
+
msgstr "Last update date"
|
|
19
|
+
|
|
20
|
+
msgid "data_ultima_modifica_description"
|
|
21
|
+
msgstr "Date in DD/MM/YYYY format. If empty, current date will be used."
|
|
22
|
+
|
|
23
|
+
msgid "map_entries_title"
|
|
24
|
+
msgstr "Link map"
|
|
25
|
+
|
|
26
|
+
msgid "map_entries_description"
|
|
27
|
+
msgstr "One line per item using key|url format. Only c.1 schema keys are allowed."
|
|
28
|
+
|
|
29
|
+
msgid "invalid_entries_line"
|
|
30
|
+
msgstr "Each row must be in 'key|url' format."
|
|
31
|
+
|
|
32
|
+
msgid "invalid_entries_key"
|
|
33
|
+
msgstr "Invalid key for selected category."
|
|
34
|
+
|
|
35
|
+
msgid "invalid_entries_url"
|
|
36
|
+
msgstr "Invalid URL."
|
|
37
|
+
|
|
38
|
+
msgid "missing_required_root_key"
|
|
39
|
+
msgstr "Please add the required root section row."
|
|
40
|
+
|
|
41
|
+
msgid "invalid_date"
|
|
42
|
+
msgstr "Date must be in DD/MM/YYYY format."
|
|
43
|
+
|
|
44
|
+
msgid "linkmap_controlpanel_title"
|
|
45
|
+
msgstr "Link Map Configuration"
|