[DOCS] Manuale d'uso COMPLETO v1.14.0: accesso/registrazione/onboarding passo-passo + 18 moduli dall'help reale
Riscrittura completa: istruzioni concrete (login, registrazione 3 step, onboarding 4 step con campi reali, navigazione), per ogni modulo "cosa trovi e come si usa" estratto dall'help contestuale del prodotto (help.js), FAQ, glossario. Rimosse le interruzioni di pagina che lasciavano pagine vuote. Generatore self-contained (estrae i contenuti da public/js/help.js via node). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0a883b7cae
commit
ae7bb072d7
Binary file not shown.
+222
-309
@@ -1,287 +1,228 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Genera il Manuale d'uso di NIS2 Agile in .docx usando solo stdlib (zipfile+XML)."""
|
"""Manuale d'uso COMPLETO di NIS2 Agile (.docx, solo stdlib). Contenuti moduli da help.js reale."""
|
||||||
import zipfile, re, datetime
|
import zipfile, re, json, html as _html, subprocess, os
|
||||||
from xml.sax.saxutils import escape
|
from xml.sax.saxutils import escape
|
||||||
|
|
||||||
OUT = "/projects/nis2-agile/docs/MANUALE_UTENTE_NIS2_AGILE.docx"
|
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # repo root
|
||||||
|
OUT = os.path.join(BASE, "docs", "MANUALE_UTENTE_NIS2_AGILE.docx")
|
||||||
# ─────────────────────────────────────────────────────────────────────────
|
HELP_JSON = "/tmp/help.json"
|
||||||
# CONTENUTO DEL MANUALE (DSL: lista di blocchi)
|
# Auto-estrae i contenuti dall'help reale del prodotto (public/js/help.js) via node.
|
||||||
# ('title', titolo, sottotitolo, riga_meta)
|
_node = ('const fs=require("fs");let s=fs.readFileSync(process.argv[1],"utf8");'
|
||||||
# ('h1'|'h2'|'h3', testo) | ('p', testo) | ('note', testo)
|
'const a=s.indexOf("var _helpContent");const start=s.indexOf("{",a);'
|
||||||
# ('ul', [voci]) | ('ol', [voci])
|
'const end=s.indexOf("var _pageMap");let obj=s.slice(start,s.lastIndexOf("}",end)+1);'
|
||||||
# ('table', [intestazioni], [[riga],...])
|
'fs.writeFileSync(process.argv[2],JSON.stringify(eval("("+obj+")")));')
|
||||||
# ('pb',) page break
|
subprocess.run(["node","-e",_node, os.path.join(BASE,"public","js","help.js"), HELP_JSON], check=True)
|
||||||
# Nel testo: **grassetto** supportato.
|
HELP = json.load(open(HELP_JSON, encoding="utf-8"))
|
||||||
# ─────────────────────────────────────────────────────────────────────────
|
|
||||||
DATE = "11 giugno 2026"
|
DATE = "11 giugno 2026"
|
||||||
|
|
||||||
C = []
|
C = []
|
||||||
def add(*b): C.append(b)
|
def add(*b): C.append(b)
|
||||||
|
|
||||||
add('title', "NIS2 Agile", "Manuale d'uso del prodotto",
|
def html2mk(s):
|
||||||
"Versione piattaforma 1.14.0 · Aggiornato all'%s" % DATE)
|
"""Converte l'HTML dell'help nel markup interno (**bold**) + testo pulito."""
|
||||||
|
s = re.sub(r'</?strong>|</?b>', '**', s)
|
||||||
|
s = re.sub(r'<[^>]+>', '', s) # rimuovi altri tag (span/em/...)
|
||||||
|
s = _html.unescape(s) # < ≥ ...
|
||||||
|
s = s.replace(' ', ' ')
|
||||||
|
s = re.sub(r'\s+', ' ', s).strip()
|
||||||
|
# bilancia eventuali ** dispari
|
||||||
|
if s.count('**') % 2: s += '**'
|
||||||
|
return s
|
||||||
|
|
||||||
# ===== INDICE (statico, i numeri di pagina non sono calcolati) =====
|
def module_chapter(num, title, topic_key, lead=None):
|
||||||
add('h1', "Indice dei contenuti")
|
t = HELP.get(topic_key, {})
|
||||||
for n in ["1. Introduzione","2. Primi passi (accesso, registrazione, onboarding)",
|
add('h1', f"{num}. {title}")
|
||||||
"3. Dashboard","4. Gap Analysis NIS2 (Art. 21)","5. Gap Analysis ACN (Determinazione 164179/2025)",
|
if lead: add('p', lead)
|
||||||
"6. Modello Organizzativo SGSI (ISO 27001/27017/27018)","7. Gestione dei Rischi",
|
if t.get('intro'): add('p', html2mk(t['intro']))
|
||||||
"8. Gestione degli Incidenti (Art. 23)","9. Policy e procedure","10. Supply Chain (fornitori)",
|
for sec in t.get('sections', []):
|
||||||
"11. Formazione","12. Asset","13. Audit & Report","14. Whistleblowing (Art. 32)",
|
add('h3', html2mk(sec.get('heading','')))
|
||||||
"15. Aggiornamenti normativi","16. Knowledge Base e Assistente AI","17. Segnalazioni (feedback)",
|
items = [html2mk(x) for x in sec.get('items', [])]
|
||||||
"18. Impostazioni","19. Amministrazione","20. Integrazioni e API","21. Glossario","22. Riferimenti normativi"]:
|
if items: add('ul', items)
|
||||||
add('p', n)
|
refs = [html2mk(x) for x in t.get('references', [])]
|
||||||
|
if refs:
|
||||||
|
add('h3', "Riferimenti normativi")
|
||||||
|
add('ul', refs)
|
||||||
|
|
||||||
|
# ══════════════════ COPERTINA ══════════════════
|
||||||
|
add('title', "NIS2 Agile", "Manuale d'uso del prodotto",
|
||||||
|
f"Guida operativa completa · Versione piattaforma 1.14.0 · {DATE}")
|
||||||
|
add('p', "Questo manuale spiega passo dopo passo come accedere alla piattaforma, registrarsi, completare l'onboarding aziendale e utilizzare ogni modulo. Per ogni schermata trovi cosa contiene, a cosa serve e come operare.")
|
||||||
add('pb')
|
add('pb')
|
||||||
|
|
||||||
# ===== 1. INTRODUZIONE =====
|
# ══════════════════ INDICE ══════════════════
|
||||||
|
add('h1', "Indice")
|
||||||
|
toc = ["1. Introduzione","2. Requisiti e accesso alla piattaforma","3. Registrazione di un nuovo utente",
|
||||||
|
"4. Onboarding: configurazione dell'azienda","5. Come muoversi nell'interfaccia","6. Dashboard",
|
||||||
|
"7. Gap Analysis NIS2 (Art. 21)","8. Gap Analysis ACN (Determinazione 164179/2025)",
|
||||||
|
"9. Modello Organizzativo SGSI (ISO 27001/27017/27018)","10. Gestione dei Rischi",
|
||||||
|
"11. Gestione degli Incidenti (Art. 23)","12. Policy e procedure","13. Supply Chain (fornitori)",
|
||||||
|
"14. Formazione","15. Asset","16. Audit & Report","17. Whistleblowing (Art. 32)",
|
||||||
|
"18. Aggiornamenti normativi","19. Knowledge Base","20. Compliance Journey","21. Segnalazioni (feedback)",
|
||||||
|
"22. Impostazioni","23. Gestione delle aziende (consulenti)","24. Domande frequenti (FAQ)",
|
||||||
|
"25. Glossario","26. Riferimenti normativi"]
|
||||||
|
for x in toc: add('p', x)
|
||||||
|
add('note', "I nomi delle voci e l'aspetto delle schermate possono variare leggermente con gli aggiornamenti. In ogni pagina è disponibile il pulsante di aiuto contestuale (icona ?) con la guida e i riferimenti normativi.")
|
||||||
|
|
||||||
|
# ══════════════════ 1. INTRODUZIONE ══════════════════
|
||||||
add('h1', "1. Introduzione")
|
add('h1', "1. Introduzione")
|
||||||
add('h2', "1.1 Che cos'è NIS2 Agile")
|
add('p', "**NIS2 Agile** è una piattaforma web (SaaS) che accompagna le aziende nella conformità alla **Direttiva (UE) 2022/2555 (NIS2)**, al suo recepimento italiano (**D.Lgs. 138/2024**) e alle **Determinazioni dell'Agenzia per la Cybersicurezza Nazionale (ACN)**. Integra l'intelligenza artificiale per gap analysis, generazione di policy, classificazione degli incidenti e suggerimento dei rischi.")
|
||||||
add('p', "NIS2 Agile è una piattaforma SaaS multi-tenant che supporta le aziende nel percorso di conformità alla **Direttiva (UE) 2022/2555 (NIS2)** e al suo recepimento italiano (**D.Lgs. 138/2024**), comprese le **Determinazioni dell'Agenzia per la Cybersicurezza Nazionale (ACN)**. Integra l'intelligenza artificiale (Claude) per gap analysis, generazione di policy, classificazione degli incidenti e suggerimento dei rischi.")
|
add('p', "Dalla versione 1.14.0 include anche il **Modello Organizzativo SGSI** secondo **ISO/IEC 27001:2022**, con estensioni cloud ISO 27017/27018.")
|
||||||
add('p', "Dalla versione 1.14.0 la piattaforma include anche un modulo guidato per la costruzione del **Modello Organizzativo SGSI secondo ISO/IEC 27001:2022**, con estensioni cloud ISO/IEC 27017:2015 e 27018:2019.")
|
add('h3', "A chi è rivolto")
|
||||||
add('h2', "1.2 A chi è rivolto")
|
add('ul', ["**PMI** che devono adeguarsi agli obblighi NIS2;",
|
||||||
add('ul', ["**PMI** che devono adeguarsi agli obblighi NIS2 con risorse limitate;",
|
"**Grandi imprese** con processi di compliance strutturati;",
|
||||||
"**Grandi imprese / Enterprise** con processi di compliance strutturati;",
|
"**Consulenti e CISO** che seguono più aziende clienti tramite uno studio."])
|
||||||
"**Consulenti e CISO** che gestiscono più organizzazioni clienti tramite uno studio (consulting firm)."])
|
add('h3', "Come è organizzato il lavoro nella piattaforma")
|
||||||
add('h2', "1.3 Quadro normativo di riferimento")
|
add('p', "Il percorso tipico è: **(1)** accedi o registrati → **(2)** completa l'onboarding dell'azienda (che ne determina la classificazione NIS2) → **(3)** esegui la Gap Analysis NIS2 → **(4)** approfondisci con la Gap Analysis ACN e costruisci il Modello SGSI → **(5)** gestisci rischi, incidenti, policy, fornitori, formazione e audit nel tempo.")
|
||||||
add('table', ["Fonte","Ruolo"],
|
add('note', "Disclaimer: NIS2 Agile è uno strumento di supporto operativo e pre-audit. Non costituisce consulenza legale né parere professionale vincolante e non rilascia certificazioni ISO. Le valutazioni proposte vanno confermate con il referente compliance/legale dell'organizzazione.")
|
||||||
[["Direttiva (UE) 2022/2555 (NIS2)","Principi e obblighi europei di cibersicurezza"],
|
|
||||||
["D.Lgs. 138/2024","Recepimento italiano della NIS2 (obblighi operativi)"],
|
|
||||||
["Determinazione ACN 164179/2025","Misure di sicurezza di base, classificazione e notifica incidenti (Allegati)"],
|
|
||||||
["ISO/IEC 27001:2022","Requisiti del Sistema di Gestione della Sicurezza delle Informazioni (best practice)"],
|
|
||||||
["ISO/IEC 27017:2015 / 27018:2019","Controlli per servizi cloud / protezione PII in cloud (best practice)"]])
|
|
||||||
add('note', "Disclaimer: NIS2 Agile è uno strumento di supporto operativo e pre-audit. Non costituisce consulenza legale né parere professionale vincolante, e non rilascia certificazioni ISO. Le valutazioni proposte (perimetro, applicabilità, significatività) vanno confermate con il referente compliance/legale dell'organizzazione.")
|
|
||||||
|
|
||||||
# ===== 2. PRIMI PASSI =====
|
# ══════════════════ 2. ACCESSO ══════════════════
|
||||||
add('pb'); add('h1', "2. Primi passi")
|
add('h1', "2. Requisiti e accesso alla piattaforma")
|
||||||
add('h2', "2.1 Accesso e indirizzo")
|
add('h3', "Requisiti")
|
||||||
add('p', "La piattaforma è raggiungibile all'indirizzo **https://nis2.agile.software/**. L'accesso avviene con email e password (autenticazione JWT). Se la tua organizzazione usa il Single Sign-On centralizzato (AgileHub), le credenziali sono condivise tra i prodotti della suite.")
|
add('ul', ["Un browser web aggiornato (Chrome, Edge, Firefox o Safari);",
|
||||||
add('h2', "2.2 Registrazione")
|
"una connessione a Internet;",
|
||||||
add('ol', ["Apri la pagina di **Registrazione** e inserisci i dati richiesti (email, password conforme alla policy di sicurezza).",
|
"le credenziali di accesso (email e password) oppure un invito ricevuto dal proprio studio/partner."])
|
||||||
"Al termine vieni indirizzato automaticamente alla procedura di **onboarding** aziendale.",
|
add('h3', "Indirizzo della piattaforma")
|
||||||
"Se possiedi un **invito/licenza** (token `inv_...`) fornito da un partner, inseriscilo per attivare l'organizzazione pre-configurata."])
|
add('p', "Apri il browser e vai su **https://nis2.agile.software/**. Si apre la pagina di accesso.")
|
||||||
add('h2', "2.3 Recupero password")
|
add('h3', "Come accedere (login)")
|
||||||
add('p', "Dalla pagina di login usa **Password dimenticata** per ricevere un link di reset via email. Il cambio password effettuato da AgileHub si propaga automaticamente entro pochi minuti grazie al sync SSO.")
|
add('ol', ["Nel campo **Indirizzo Email** inserisci l'email con cui sei registrato (es. nome@azienda.it).",
|
||||||
add('h2', "2.4 Onboarding dell'organizzazione")
|
"Nel campo **Password** inserisci la tua password. Puoi usare l'icona a forma di occhio per mostrarla/nasconderla.",
|
||||||
add('p', "Il wizard di onboarding crea l'organizzazione e ne determina la classificazione NIS2. Si articola in quattro passi:")
|
"Premi **Accedi**.",
|
||||||
add('ol', ["**Dati azienda** — inserimento manuale oppure precompilazione tramite **Partita IVA** (lookup automatico) o caricamento della **visura camerale** (estrazione AI dei dati).",
|
"Se le credenziali sono corrette: se hai già un'azienda configurata vieni portato alla **Dashboard**, altrimenti alla procedura di **Onboarding**."])
|
||||||
"**Verifica e completamento** — settore (ATECO → settore NIS2), numero dipendenti, fatturato, sede, contatti.",
|
add('p', "In caso di errore compare un messaggio in rosso sotto il titolo. Verifica email e password e riprova.")
|
||||||
"**Profilo utente** — nome, ruolo, telefono.",
|
add('h3', "Password dimenticata")
|
||||||
"**Classificazione NIS2** — la piattaforma propone se il soggetto è **essenziale**, **importante** o **non applicabile** in base a settore e dimensione; è possibile aderire volontariamente."])
|
add('ol', ["Dalla pagina di accesso scegli **Password dimenticata**.",
|
||||||
add('note', "La classificazione (essenziale/importante) determina il perimetro applicabile in più moduli, in particolare la Gap Analysis ACN e gli obblighi sugli incidenti. Puoi rivederla in Impostazioni › Classificazione NIS2.")
|
"Inserisci l'email dell'account: riceverai un messaggio con un link per impostare una nuova password.",
|
||||||
add('h2', "2.5 Ruoli e permessi")
|
"Apri il link, scegli la nuova password (rispettando i requisiti di sicurezza) e conferma."])
|
||||||
add('table', ["Ruolo","Descrizione"],
|
add('note', "Se la tua azienda usa il Single Sign-On della suite (AgileHub), la password è condivisa tra i prodotti: un cambio password si propaga automaticamente entro pochi minuti.")
|
||||||
[["super_admin","Amministratore di piattaforma (accesso a tutte le organizzazioni)"],
|
add('h3', "Disconnessione e sessioni")
|
||||||
["org_admin","Amministratore dell'organizzazione"],
|
add('p', "Per uscire usa la voce **Esci/Logout** nel menu utente. Dalle Impostazioni puoi vedere i **dispositivi collegati** (sessioni attive) e revocarli singolarmente o tutti.")
|
||||||
["compliance_manager","Responsabile compliance: gestisce assessment, rischi, policy, SGSI"],
|
|
||||||
["board_member","Organo direttivo: visione e approvazioni"],
|
|
||||||
["auditor","Revisore: lettura e compilazione evidenze/controlli"],
|
|
||||||
["employee","Dipendente: formazione, segnalazioni"],
|
|
||||||
["consultant","Consulente di studio che opera su più organizzazioni clienti"]])
|
|
||||||
add('h2', "2.6 Multi-organizzazione, lingua e aiuto")
|
|
||||||
add('ul', ["Chi appartiene a più organizzazioni (es. consulenti) può **cambiare contesto** dall'intestazione/menu.",
|
|
||||||
"L'interfaccia è disponibile in **Italiano** ed **Inglese** (selettore lingua).",
|
|
||||||
"Ogni pagina dispone di **Aiuto contestuale** (icona ?) con guida e riferimenti normativi certi."])
|
|
||||||
|
|
||||||
# ===== 3. DASHBOARD =====
|
# ══════════════════ 3. REGISTRAZIONE ══════════════════
|
||||||
add('pb'); add('h1', "3. Dashboard")
|
add('h1', "3. Registrazione di un nuovo utente")
|
||||||
add('p', "La Dashboard è la pagina iniziale dopo l'accesso e offre una visione d'insieme dello stato di conformità.")
|
add('p', "Se non hai un account, dalla pagina di accesso scegli **Registrati**. La registrazione è una procedura guidata in tre passi, con un indicatore di avanzamento in alto.")
|
||||||
add('ul', ["**Avanzamento implementazione misure Art. 21 NIS2** — indicatore complessivo (gauge);",
|
add('h3', "Passo 1 — Ruolo e (eventuale) codice invito")
|
||||||
"**Scadenze imminenti** — adempimenti e revisioni in arrivo da più moduli;",
|
add('p', "Scegli il **ruolo** con cui ti registri, selezionando una delle schede disponibili:")
|
||||||
"**Attività recenti** — ultime azioni tracciate;",
|
add('table', ["Scheda ruolo","Quando sceglierlo"],
|
||||||
"**Heatmap dei rischi** — distribuzione dei rischi su probabilità × impatto;",
|
[["Responsabile compliance","Gestisci direttamente assessment, rischi, policy e SGSI dell'azienda"],
|
||||||
"**Benchmark settoriale** (anonimizzato) — confronto con il proprio settore;",
|
["Amministratore organizzazione","Amministri l'azienda, gli utenti e le impostazioni"],
|
||||||
"**Compliance Journey** — percorso guidato che indica i prossimi passi consigliati."])
|
["Consulente","Segui più aziende clienti per conto di uno studio"],
|
||||||
|
["Auditor","Esegui verifiche e compili evidenze/controlli (lettura prevalente)"],
|
||||||
|
["Membro del board","Organo direttivo: visione e approvazioni"]])
|
||||||
|
add('p', "Se hai ricevuto un **Codice Invito** da un partner o dal tuo studio (formato `inv_...`), inseriscilo nell'apposito campo: il sistema lo verifica e mostra l'azienda/piano associati. Premi **Avanti** per proseguire.")
|
||||||
|
add('h3', "Passo 2 — Dati personali e password")
|
||||||
|
add('ul', ["**Nome** e **Cognome** (es. Mario Rossi);",
|
||||||
|
"**Email** (sarà il tuo identificativo di accesso);",
|
||||||
|
"eventuale **Partita IVA** dell'azienda (verificata in tempo reale, dove richiesto);",
|
||||||
|
"**Password** (minimo 8 caratteri): un indicatore mostra la robustezza della password mentre la digiti;",
|
||||||
|
"**Conferma password**: ripeti la stessa password."])
|
||||||
|
add('h3', "Passo 3 — Conferma e avvio")
|
||||||
|
add('p', "Rivedi i dati, accetta le condizioni e completa la registrazione. Al termine vieni indirizzato automaticamente all'**Onboarding** per configurare l'azienda (se non sei entrato tramite un invito che la pre-configura).")
|
||||||
|
|
||||||
# ===== 4. GAP ANALYSIS NIS2 =====
|
# ══════════════════ 4. ONBOARDING ══════════════════
|
||||||
add('pb'); add('h1', "4. Gap Analysis NIS2 (Art. 21)")
|
add('h1', "4. Onboarding: configurazione dell'azienda")
|
||||||
add('p', "Analisi di **primo livello** sulle 10 categorie di misure dell'Art. 21.2 NIS2, basata su un questionario di 80 domande (10 categorie), ciascuna collegata anche al controllo ISO 27001 corrispondente.")
|
add('p', "L'onboarding crea l'organizzazione e ne stabilisce la **classificazione NIS2** (essenziale, importante o non applicabile), che determina gli obblighi e il perimetro applicabile negli altri moduli. È una procedura guidata con uno **stepper** in alto che mostra i passi.")
|
||||||
add('h2', "4.1 Come si svolge")
|
add('h3', "Passo 1 — Inserisci la Partita IVA")
|
||||||
add('ol', ["Crea un nuovo assessment: la piattaforma pre-popola tutte le domande.",
|
add('p', "Nella prima schermata (\"Inserisci la Partita IVA dell'azienda\") digiti la **Partita IVA** (es. 12345678901) e premi il pulsante di ricerca: la piattaforma tenta di **recuperare automaticamente** i dati aziendali. In alternativa puoi caricare la **visura camerale** (i dati vengono estratti dall'AI) oppure proseguire e inserire tutto manualmente. Premi **Continua**.")
|
||||||
"Per ogni domanda indica lo stato: **Attuato**, **Parziale**, **Non attuato**, **Non applicabile**. Le risposte si salvano automaticamente.",
|
add('h3', "Passo 2 — Verifica e completa i dati aziendali")
|
||||||
"Completa l'assessment per ottenere un **punteggio** per categoria e complessivo.",
|
add('p', "Nella schermata \"Verifica e Completa i Dati Aziendali\" un banner indica la fonte dei dati (visura, lookup P.IVA o inserimento manuale). Controlla e completa i campi:")
|
||||||
"Avvia l'**analisi AI** per ricevere sintesi esecutiva, priorità, quick win e una roadmap di conformità."])
|
add('ul', ["**Ragione sociale** (es. Acme S.r.l.);",
|
||||||
add('note', "Le risposte della Gap Analysis NIS2 alimentano automaticamente il Modello SGSI (capitolo 6): il loro stato pre-popola lo Statement of Applicability ISO 27001.")
|
"**Partita IVA** e **Codice Fiscale**;",
|
||||||
|
"**Indirizzo**, **Città**, **Sito web**;",
|
||||||
|
"**Email aziendale** e **Telefono aziendale**;",
|
||||||
|
"**Settore** — scegli dall'elenco il settore NIS2 (es. Energia, Trasporti, Sanità, Infrastrutture digitali, ecc.): è determinante per la classificazione;",
|
||||||
|
"**Numero di dipendenti** e **fatturato** annuo, usati per stabilire la dimensione dell'impresa."])
|
||||||
|
add('h3', "Passo 3 — Il tuo profilo")
|
||||||
|
add('p', "Inserisci i dati del tuo profilo utente: **nome completo**, **ruolo** in azienda e **telefono** di contatto.")
|
||||||
|
add('h3', "Passo 4 — Classificazione NIS2")
|
||||||
|
add('p', "In base a settore e dimensione, la piattaforma **propone la classificazione**: soggetto **essenziale**, **importante** oppure **non applicabile**. Se non rientri obbligatoriamente ma vuoi adeguarti, puoi indicare l'**adesione volontaria**. Conferma per completare l'onboarding e accedere alla Dashboard.")
|
||||||
|
add('note', "Puoi rivedere o aggiornare la classificazione in qualsiasi momento da Impostazioni › Classificazione NIS2. La classificazione filtra automaticamente, ad esempio, i requisiti applicabili nella Gap Analysis ACN e gli obblighi sugli incidenti.")
|
||||||
|
|
||||||
# ===== 5. GAP ANALYSIS ACN =====
|
# ══════════════════ 5. NAVIGAZIONE ══════════════════
|
||||||
add('pb'); add('h1', "5. Gap Analysis ACN (Determinazione 164179/2025)")
|
add('h1', "5. Come muoversi nell'interfaccia")
|
||||||
add('p', "Analisi di **secondo livello** sulle misure e i requisiti puntuali stabiliti dall'ACN, articolati secondo il **Framework Nazionale** (funzioni Governo GV, Identificazione ID, Protezione PR, Rilevamento DE, Risposta RS, Ripristino RC).")
|
add('p', "Dopo l'accesso l'interfaccia è composta da una **barra laterale** (sidebar) a sinistra con il menu, e dall'**area principale** a destra che mostra la pagina selezionata. In alto a destra di ogni pagina trovi il pulsante di **aiuto contestuale (?)** e le azioni della pagina.")
|
||||||
add('table', ["Classificazione","Perimetro applicabile"],
|
add('h3', "Le sezioni del menu")
|
||||||
[["Soggetto IMPORTANTE (Allegato 1)","37 misure / 87 requisiti"],
|
add('table', ["Sezione","Voci"],
|
||||||
["Soggetto ESSENZIALE (Allegato 2)","43 misure / 116 requisiti"]])
|
[["Principale","Dashboard, Compliance Journey, Gap Analysis (NIS2), Gap Analysis ACN, Modello SGSI (ISO 27001)"],
|
||||||
add('ul', ["Il perimetro è filtrato automaticamente in base alla classificazione NIS2 dell'organizzazione;",
|
["Gestione","Rischi, Incidenti, Policy, Supply Chain, Segnalazioni (whistleblowing), Normative, AI Cross-Analysis, Knowledge Base"],
|
||||||
"scoring per funzione del Framework Nazionale e punteggio complessivo;",
|
["Operativo","Formazione, Asset, Audit & Report"],
|
||||||
"**piano d'azione** dei requisiti non conformi e **analisi AI** ancorata ai 203 requisiti ACN reali (nessun riferimento inventato);",
|
["Sistema","Guida all'uso, Impostazioni, Architettura, Simulazione Demo, Integrazioni Esterne"]])
|
||||||
"**Catalogo requisiti** consultabile in sola lettura."])
|
add('h3', "Lingua e aiuto")
|
||||||
|
add('ul', ["L'interfaccia è disponibile in **Italiano** ed **Inglese** (selettore lingua).",
|
||||||
|
"Il pulsante **?** in ogni pagina apre la guida contestuale con spiegazioni e riferimenti normativi.",
|
||||||
|
"Chi appartiene a più aziende (consulenti) può **cambiare organizzazione** dal menu."])
|
||||||
|
|
||||||
# ===== 6. MODELLO SGSI ISO 27001 (NUOVO) =====
|
# ══════════════════ 6..23 MODULI (da help.js) ══════════════════
|
||||||
add('pb'); add('h1', "6. Modello Organizzativo SGSI (ISO 27001/27017/27018)")
|
module_chapter(6, "Dashboard", "dashboard")
|
||||||
add('p', "Procedura guidata per costruire il **Sistema di Gestione della Sicurezza delle Informazioni (SGSI / ISMS)** secondo **ISO/IEC 27001:2022** (clausole 4–10) e il relativo **Statement of Applicability (SoA)** sui 93 controlli dell'Annex A. È uno strumento di supporto e pre-audit, non una certificazione.")
|
module_chapter(7, "Gap Analysis NIS2 (Art. 21)", "assessment",
|
||||||
add('h2', "6.1 Il wizard in 6 passi")
|
"Apri la voce **Gap Analysis** dal menu. È l'analisi di primo livello sulle 10 categorie di misure dell'Art. 21 NIS2.")
|
||||||
add('table', ["Passo","Clausola ISO 27001","Contenuto"],
|
module_chapter(8, "Gap Analysis ACN (Determinazione 164179/2025)", "acn",
|
||||||
[["1. Contesto e Ambito","cl. 4","Scope del SGSI, contesto interno/esterno, parti interessate, confini, esclusioni motivate, attivazione estensioni cloud"],
|
"Apri la voce **Gap Analysis ACN**. È l'analisi di secondo livello sui requisiti puntuali ACN.")
|
||||||
["2. Leadership","cl. 5","Ruoli e responsabilità con matrice RACI (Responsible, Accountable, Consulted, Informed)"],
|
module_chapter(9, "Modello Organizzativo SGSI (ISO 27001/27017/27018)", "isms",
|
||||||
["3. Risk","cl. 6","Metodologia di risk assessment e obiettivi del SGSI (il registro rischi resta nel modulo Rischi)"],
|
"Apri la voce **Modello SGSI (ISO 27001)**. Una procedura guidata in 6 passi costruisce il Sistema di Gestione della Sicurezza delle Informazioni; lo Statement of Applicability è pre-popolato dalle risposte della Gap Analysis NIS2.")
|
||||||
["4. Statement of Applicability","cl. 6.1.3","Applicabilità, stato e motivazione dei 93 controlli Annex A + estensioni cloud"],
|
module_chapter(10, "Gestione dei Rischi", "risks", "Apri la voce **Rischi**.")
|
||||||
["5. Documented Information","cl. 7–8","Policy e procedure, con bozze generabili dall'AI"],
|
module_chapter(11, "Gestione degli Incidenti (Art. 23)", "incidents", "Apri la voce **Incidenti**.")
|
||||||
["6. Monitoraggio e Miglioramento","cl. 9–10","Audit interni e non conformità (moduli Audit & Report e NCR/CAPA); checklist di completamento"]])
|
module_chapter(12, "Policy e procedure", "policies", "Apri la voce **Policy**.")
|
||||||
add('h2', "6.2 SoA pre-popolato dalla Gap Analysis NIS2")
|
module_chapter(13, "Supply Chain (fornitori)", "supply-chain", "Apri la voce **Supply Chain**.")
|
||||||
add('p', "Ogni domanda della Gap Analysis NIS2 è collegata a un controllo ISO 27001 (es. A.5.1). Per questo lo Statement of Applicability viene **pre-compilato** a partire dalle risposte NIS2 già date: i controlli con corrispondenza riportano il badge **\"da NIS2\"** e uno stato proposto (Attuato = 100%, Parziale = 50%, Non attuato = 0%). I controlli non coperti dal NIS2 (es. parte dei controlli fisici A.7) restano da compilare manualmente.")
|
module_chapter(14, "Formazione", "training", "Apri la voce **Formazione**.")
|
||||||
add('note', "Il pulsante \"Ri-deriva dal NIS2\" aggiunge soltanto i controlli mancanti e non sovrascrive le modifiche manuali già inserite.")
|
module_chapter(15, "Asset", "assets", "Apri la voce **Asset**.")
|
||||||
add('h2', "6.3 Estensioni cloud (condizionali)")
|
module_chapter(16, "Audit & Report", "reports", "Apri la voce **Audit & Report**.")
|
||||||
add('ul', ["**ISO/IEC 27017:2015** — attivala se usi servizi cloud pubblici o sei un fornitore cloud: aggiunge 7 controlli cloud (CLD.*) al SoA;",
|
module_chapter(17, "Whistleblowing (Art. 32)", "whistleblowing", "Apri la voce **Segnalazioni**.")
|
||||||
"**ISO/IEC 27018:2019** — attivala se tratti dati personali (PII) in cloud pubblico come responsabile: aggiunge i controlli privacy (PII.*), sinergici con il GDPR.",
|
module_chapter(18, "Aggiornamenti normativi", "normative", "Apri la voce **Normative**.")
|
||||||
"Le sezioni cloud/PII compaiono nel SoA **solo** se attivi i relativi flag nel passo 1."])
|
module_chapter(19, "Knowledge Base", "kb", "Apri la voce **Knowledge Base**.")
|
||||||
add('h2', "6.4 Documenti e generazione AI")
|
module_chapter(20, "Compliance Journey", "workflow", "Apri la voce **Compliance Journey**: un percorso guidato che indica i prossimi passi consigliati.")
|
||||||
add('p', "Nel passo 5 puoi generare bozze di policy e procedure (Policy SGSI, Dichiarazione di Applicabilità, controllo accessi, gestione incidenti, continuità, sicurezza fornitori). Le bozze sono prodotte dall'AI con ancoraggio alle fonti certe e richiedono **revisione umana** prima dell'approvazione.")
|
module_chapter(21, "Segnalazioni (feedback)", "feedback",
|
||||||
add('h2', "6.5 Esportazione")
|
"Usa lo strumento di feedback per segnalare problemi o suggerimenti: ogni segnalazione cattura automaticamente versione e superficie del prodotto.")
|
||||||
add('p', "Il pulsante **Esporta SGSI** apre una versione stampabile del modello (ambito, metodologia, SoA con stato dei controlli), utile come evidenza in vista di un audit.")
|
module_chapter(22, "Impostazioni", "settings", "Apri la voce **Impostazioni**.")
|
||||||
|
module_chapter(23, "Gestione delle aziende (consulenti)", "companies",
|
||||||
|
"Disponibile per i consulenti: consente di gestire più aziende clienti da un unico accesso.")
|
||||||
|
|
||||||
# ===== 7. RISCHI =====
|
# ══════════════════ 24. FAQ ══════════════════
|
||||||
add('pb'); add('h1', "7. Gestione dei Rischi")
|
add('h1', "24. Domande frequenti (FAQ)")
|
||||||
add('p', "Registro dei rischi con matrice **Probabilità × Impatto 5×5** e supporto AI, conforme all'Art. 21 NIS2 e alla metodologia ISO 27005.")
|
add('h3', "Non riesco ad accedere")
|
||||||
add('ul', ["Creazione del rischio con scala probabilità/impatto (dettagli ISO 27005);",
|
add('p', "Verifica email e password; usa **Password dimenticata** per reimpostarla. Se usi il SSO della suite, accedi con le credenziali centralizzate.")
|
||||||
"**Piani di trattamento** (mitigare, accettare, trasferire, evitare) e stato di avanzamento;",
|
add('h3', "Ho sbagliato la classificazione NIS2")
|
||||||
"**Suggerimento AI** dei rischi per settore e asset (dati anonimizzati);",
|
add('p', "Puoi correggerla in **Impostazioni › Classificazione NIS2**: il perimetro dei moduli (es. Gap Analysis ACN) si aggiorna di conseguenza.")
|
||||||
"Funzioni avanzate: registro quantitativo **FAIR** (calcolo ALE Monte Carlo) e dashboard **KRI**."])
|
add('h3', "Lo Statement of Applicability del Modello SGSI è quasi vuoto")
|
||||||
|
add('p', "Viene pre-popolato dalle risposte della **Gap Analysis NIS2**: completa prima quell'assessment, poi usa **Ri-deriva dal NIS2** nel SoA. I controlli senza corrispondenza NIS2 (es. alcuni controlli fisici) vanno compilati manualmente.")
|
||||||
|
add('h3', "Le email non vengono inviate")
|
||||||
|
add('p', "Negli ambienti dimostrativi l'invio email può essere disattivato per sicurezza. In produzione le notifiche (CSIRT, formazione, inviti) vengono inviate regolarmente.")
|
||||||
|
add('h3', "Le bozze generate dall'AI sono definitive?")
|
||||||
|
add('p', "No: sono **bozze** da rivedere e approvare. Riportano sempre un avviso e citano le fonti normative.")
|
||||||
|
|
||||||
# ===== 8. INCIDENTI =====
|
# ══════════════════ 25. GLOSSARIO ══════════════════
|
||||||
add('pb'); add('h1', "8. Gestione degli Incidenti (Art. 23)")
|
add('h1', "25. Glossario")
|
||||||
add('p', "Gestione del ciclo di vita degli incidenti significativi e degli obblighi di notifica al CSIRT secondo l'Art. 23 e la Determinazione ACN 164179/2025.")
|
|
||||||
add('h2', "8.1 Tempistiche di notifica")
|
|
||||||
add('table', ["Adempimento","Termine"],
|
|
||||||
[["Pre-allarme (early warning)","entro 24 ore dalla conoscenza"],
|
|
||||||
["Notifica completa","entro 72 ore dalla conoscenza"],
|
|
||||||
["Relazione finale","entro 1 mese dalla notifica delle 72 ore"]])
|
|
||||||
add('h2', "8.2 Funzioni")
|
|
||||||
add('ul', ["**Albero decisionale** per valutare la significatività (utenti ≥ 500, durata > 4h, cross-border, attacco cyber, danni > €100k);",
|
|
||||||
"**timeline** dell'incidente e metriche (triage, contenimento, eradicazione, ripristino);",
|
|
||||||
"invio di **early warning, notifica e relazione finale** al CSIRT;",
|
|
||||||
"**classificazione AI** (tipo IS-1..IS-4, severità) con citazione della fonte (Allegato 3 = importanti, Allegato 4 = essenziali);",
|
|
||||||
"**PIR** (Post-Incident Review) per l'apprendimento."])
|
|
||||||
|
|
||||||
# ===== 9. POLICY =====
|
|
||||||
add('pb'); add('h1', "9. Policy e procedure")
|
|
||||||
add('ul', ["Creazione di policy da **template** o **generazione AI** (bozze marcate da revisionare);",
|
|
||||||
"flusso di **approvazione** e **versioning** con confronto delle versioni (diff);",
|
|
||||||
"**attestazione** di presa visione da parte del personale e relativo tracciamento."])
|
|
||||||
add('note', "Le bozze generate dall'AI riportano un banner di avviso: vanno riviste e approvate da un responsabile prima della pubblicazione.")
|
|
||||||
|
|
||||||
# ===== 10. SUPPLY CHAIN =====
|
|
||||||
add('pb'); add('h1', "10. Supply Chain (fornitori)")
|
|
||||||
add('p', "Gestione della sicurezza della catena di approvvigionamento (Art. 21.2.d).")
|
|
||||||
add('ul', ["Anagrafica fornitori, categorie e **import** massivo;",
|
|
||||||
"**questionari** configurabili (categorie, template, domande) inviati ai fornitori;",
|
|
||||||
"**portale fornitore** dedicato con accesso separato via OTP/magic-link (autosalvataggio risposte);",
|
|
||||||
"**campagne** di valutazione e cruscotto del rischio fornitori (risk overview)."])
|
|
||||||
|
|
||||||
# ===== 11. FORMAZIONE =====
|
|
||||||
add('pb'); add('h1', "11. Formazione")
|
|
||||||
add('p', "Gestione della formazione e dell'igiene informatica (Art. 21.2.g) e degli obblighi formativi per gli organi direttivi (Art. 20).")
|
|
||||||
add('ul', ["Catalogo **corsi** e **assegnazioni** al personale;",
|
|
||||||
"monitoraggio della **compliance formativa** e dei corsi obbligatori non completati."])
|
|
||||||
|
|
||||||
# ===== 12. ASSET =====
|
|
||||||
add('pb'); add('h1', "12. Asset")
|
|
||||||
add('p', "Inventario degli asset informativi e delle dipendenze.")
|
|
||||||
add('ul', ["Anagrafica asset e **import** (CMDB/cloud);",
|
|
||||||
"**scoring di rilevanza NIS2** (0–100, criterio GV.OC-04) e classificazione dei sistemi rilevanti;",
|
|
||||||
"**mappa delle dipendenze** tra asset."])
|
|
||||||
|
|
||||||
# ===== 13. AUDIT & REPORT =====
|
|
||||||
add('pb'); add('h1', "13. Audit & Report")
|
|
||||||
add('ul', ["Gestione dei **controlli di conformità** (framework NIS2 / ISO 27001) con stato ed evidenze;",
|
|
||||||
"caricamento **evidenze** e registro dei **log di audit**;",
|
|
||||||
"**mappature**: NIS2 ↔ ISO 27001 e NIST CSF 2.0; **registro dei sistemi rilevanti** (GV.OC-04);",
|
|
||||||
"**report esecutivo** stampabile ed **export CSV**;",
|
|
||||||
"**catena di integrità (hash chain SHA-256)**: ogni voce del log è concatenata alla precedente; verifica integrità ed **export certificato**."])
|
|
||||||
|
|
||||||
# ===== 14. WHISTLEBLOWING =====
|
|
||||||
add('pb'); add('h1', "14. Whistleblowing (Art. 32)")
|
|
||||||
add('p', "Canale per le segnalazioni, anche anonime.")
|
|
||||||
add('ul', ["Invio segnalazione (anche **anonima**, con codice di tracciamento);",
|
|
||||||
"assegnazione, gestione e chiusura della segnalazione;",
|
|
||||||
"consultazione anonima dello stato tramite codice di tracciamento."])
|
|
||||||
|
|
||||||
# ===== 15. NORMATIVE =====
|
|
||||||
add('pb'); add('h1', "15. Aggiornamenti normativi")
|
|
||||||
add('ul', ["Feed degli aggiornamenti **NIS2 / ACN / DORA**;",
|
|
||||||
"presa visione (**ACK**) tracciata per ciascun aggiornamento;",
|
|
||||||
"elenco aggiornamenti **in attesa** di presa visione e statistiche."])
|
|
||||||
|
|
||||||
# ===== 16. KB & AI =====
|
|
||||||
add('pb'); add('h1', "16. Knowledge Base e Assistente AI")
|
|
||||||
add('h2', "16.1 Knowledge Base (RAG)")
|
|
||||||
add('p', "La Knowledge Base alimenta le risposte dell'AI tramite ricerca semantica (RAG). Prevede tre livelli di visibilità:")
|
|
||||||
add('table', ["Livello","Chi possiede","Chi vede"],
|
|
||||||
[["SYSTEM","Fornitore della piattaforma","Tutti gli utenti"],
|
|
||||||
["FIRM","Studio di consulenza","Collaboratori dello studio + organizzazioni condivise"],
|
|
||||||
["ORG","Singola organizzazione","Solo gli utenti di quella organizzazione"]])
|
|
||||||
add('ul', ["Caricamento documenti (testo) con scelta dello scope;",
|
|
||||||
"ricerca semantica e cancellazione documenti;",
|
|
||||||
"le fonti normative certe (NIS2, D.Lgs. 138/2024, Determinazioni ACN) e i cataloghi **ISO 27001/27002/27017/27018** sono già indicizzati a livello SYSTEM."])
|
|
||||||
add('h2', "16.2 Assistente AI")
|
|
||||||
add('p', "L'assistente risponde alle domande pescando dalla Knowledge Base e **cita sempre la fonte normativa pertinente**, senza inventare riferimenti. Le risposte sono di orientamento operativo e non sostituiscono il parere legale.")
|
|
||||||
|
|
||||||
# ===== 17. FEEDBACK =====
|
|
||||||
add('pb'); add('h1', "17. Segnalazioni (feedback)")
|
|
||||||
add('p', "Strumento integrato per segnalare bug o suggerimenti di UX. Le segnalazioni vengono classificate dall'AI e, una volta risolte, l'esito può essere comunicato ai membri dell'organizzazione. Ogni segnalazione cattura automaticamente la **versione del prodotto** e la **superficie** (web/mobile) per facilitare la diagnosi.")
|
|
||||||
|
|
||||||
# ===== 18. IMPOSTAZIONI =====
|
|
||||||
add('pb'); add('h1', "18. Impostazioni")
|
|
||||||
add('ul', ["**Organizzazione** — dati, classificazione NIS2;",
|
|
||||||
"**Profilo** — dati personali, cambio password, preferenze;",
|
|
||||||
"**Membri** — invito e gestione degli utenti e dei ruoli;",
|
|
||||||
"**Sessioni** — gestione dei dispositivi collegati (multi-device) e revoca;",
|
|
||||||
"**Branding** (white-label per studi) — personalizzazione per lo studio di consulenza."])
|
|
||||||
|
|
||||||
# ===== 19. AMMINISTRAZIONE =====
|
|
||||||
add('pb'); add('h1', "19. Amministrazione")
|
|
||||||
add('p', "Area riservata al ruolo **super_admin**: gestione delle organizzazioni, degli utenti e statistiche di piattaforma.")
|
|
||||||
|
|
||||||
# ===== 20. INTEGRAZIONI E API =====
|
|
||||||
add('pb'); add('h1', "20. Integrazioni e API")
|
|
||||||
add('ul', ["**Services API** (autenticazione tramite API Key con scope) per integrazioni esterne, es. GRC/231: gap-analysis, misure, incidenti, formazione, scadenze e snapshot completo;",
|
|
||||||
"**Webhook** con firma HMAC-SHA256 e retry, per notifiche verso sistemi terzi;",
|
|
||||||
"**Licenze/inviti B2B** per provisioning di organizzazioni da parte di partner;",
|
|
||||||
"**SSO** centralizzato della suite AgileHub (sincronizzazione password)."])
|
|
||||||
|
|
||||||
# ===== 21. GLOSSARIO =====
|
|
||||||
add('pb'); add('h1', "21. Glossario")
|
|
||||||
add('table', ["Termine","Significato"],
|
add('table', ["Termine","Significato"],
|
||||||
[["NIS2","Direttiva (UE) 2022/2555 sulla cibersicurezza"],
|
[["NIS2","Direttiva (UE) 2022/2555 sulla cibersicurezza"],
|
||||||
["ACN","Agenzia per la Cybersicurezza Nazionale"],
|
["ACN","Agenzia per la Cybersicurezza Nazionale"],
|
||||||
|
["Soggetto essenziale / importante","Categorie NIS2 che determinano gli obblighi applicabili"],
|
||||||
|
["Gap Analysis","Analisi degli scostamenti tra stato attuale e requisiti"],
|
||||||
["SGSI / ISMS","Sistema di Gestione della Sicurezza delle Informazioni (ISO 27001)"],
|
["SGSI / ISMS","Sistema di Gestione della Sicurezza delle Informazioni (ISO 27001)"],
|
||||||
["SoA","Statement of Applicability: dichiarazione di applicabilità dei controlli"],
|
["SoA","Statement of Applicability: dichiarazione di applicabilità dei controlli"],
|
||||||
["Annex A","Elenco dei 93 controlli di sicurezza di ISO/IEC 27001:2022"],
|
["Annex A","I 93 controlli di sicurezza di ISO/IEC 27001:2022"],
|
||||||
["RACI","Matrice di responsabilità: Responsible, Accountable, Consulted, Informed"],
|
["RACI","Matrice di responsabilità: Responsible, Accountable, Consulted, Informed"],
|
||||||
["CSIRT","Computer Security Incident Response Team (autorità di notifica)"],
|
["CSIRT","Squadra nazionale di risposta agli incidenti (autorità di notifica)"],
|
||||||
|
["NCR / CAPA","Non conformità / azioni correttive e preventive"],
|
||||||
["PIR","Post-Incident Review (revisione post-incidente)"],
|
["PIR","Post-Incident Review (revisione post-incidente)"],
|
||||||
["RAG","Retrieval-Augmented Generation: AI con recupero da knowledge base"],
|
["RAG","Recupero da knowledge base a supporto delle risposte AI"],
|
||||||
["PII","Personally Identifiable Information (dati personali)"],
|
["PII","Dati personali (Personally Identifiable Information)"]])
|
||||||
["Soggetto essenziale / importante","Categorie NIS2 che determinano gli obblighi applicabili"]])
|
|
||||||
|
|
||||||
# ===== 22. RIFERIMENTI NORMATIVI =====
|
# ══════════════════ 26. RIFERIMENTI ══════════════════
|
||||||
add('pb'); add('h1', "22. Riferimenti normativi")
|
add('h1', "26. Riferimenti normativi")
|
||||||
add('ul', ["Direttiva (UE) 2022/2555 (NIS2);",
|
add('ul', ["Direttiva (UE) 2022/2555 (NIS2);",
|
||||||
"Direttiva (UE) 2022/2557 (CER);",
|
"Direttiva (UE) 2022/2557 (CER);",
|
||||||
"D.Lgs. 4 settembre 2024, n. 138;",
|
"D.Lgs. 4 settembre 2024, n. 138;",
|
||||||
"Determinazione ACN n. 164179 del 14/04/2025 (misure di base, classificazione e notifica incidenti, Allegati);",
|
"Determinazione ACN n. 164179 del 14/04/2025 (misure di base, classificazione e notifica incidenti);",
|
||||||
"Determinazione ACN n. 333017/2025 (piattaforma ACN, designazione rappresentanti);",
|
"Determinazione ACN n. 333017/2025;",
|
||||||
"ISO/IEC 27001:2022, 27002:2022, 27017:2015, 27018:2019 (best practice, non vincolanti)."])
|
"ISO/IEC 27001:2022, 27002:2022, 27017:2015, 27018:2019 (best practice, non vincolanti)."])
|
||||||
add('note', "Questo manuale descrive le funzionalità della piattaforma NIS2 Agile alla versione 1.14.0. Le schermate e le voci di menu possono variare con gli aggiornamenti. Per l'aiuto contestuale usa l'icona ? presente in ogni pagina.")
|
add('note', f"Manuale d'uso di NIS2 Agile — versione piattaforma 1.14.0, aggiornato all'{DATE}. Per assistenza usa il pulsante di aiuto (?) presente in ogni pagina o la voce \"Guida all'uso\" nel menu.")
|
||||||
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────
|
# ════════════════════════════════ EMITTER OOXML ════════════════════════════════
|
||||||
# EMITTER OOXML
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────
|
|
||||||
def runs(text):
|
def runs(text):
|
||||||
"""Converte **bold** in run WordprocessingML."""
|
|
||||||
out = []
|
out = []
|
||||||
for i, part in enumerate(re.split(r'\*\*', text)):
|
for i, part in enumerate(re.split(r'\*\*', text)):
|
||||||
if part == '':
|
if part == '': continue
|
||||||
continue
|
rpr = '<w:rPr><w:b/></w:rPr>' if (i % 2 == 1) else ''
|
||||||
bold = (i % 2 == 1)
|
|
||||||
rpr = '<w:rPr><w:b/></w:rPr>' if bold else ''
|
|
||||||
out.append('<w:r>%s<w:t xml:space="preserve">%s</w:t></w:r>' % (rpr, escape(part)))
|
out.append('<w:r>%s<w:t xml:space="preserve">%s</w:t></w:r>' % (rpr, escape(part)))
|
||||||
return ''.join(out) or '<w:r><w:t/></w:r>'
|
return ''.join(out) or '<w:r><w:t/></w:r>'
|
||||||
|
|
||||||
@@ -294,62 +235,48 @@ def listitem(text, numid):
|
|||||||
'<w:numPr><w:ilvl w:val="0"/><w:numId w:val="%d"/></w:numPr></w:pPr>%s</w:p>' % (numid, runs(text)))
|
'<w:numPr><w:ilvl w:val="0"/><w:numId w:val="%d"/></w:numPr></w:pPr>%s</w:p>' % (numid, runs(text)))
|
||||||
|
|
||||||
def cell(text, header=False):
|
def cell(text, header=False):
|
||||||
shd = '<w:shd w:val="clear" w:fill="1F3864"/>' if header else ''
|
|
||||||
t = ('**%s**' % text) if header else text
|
|
||||||
# nelle intestazioni il testo bianco
|
|
||||||
if header:
|
if header:
|
||||||
|
shd = '<w:shd w:val="clear" w:fill="1F3864"/>'
|
||||||
r = '<w:r><w:rPr><w:b/><w:color w:val="FFFFFF"/></w:rPr><w:t xml:space="preserve">%s</w:t></w:r>' % escape(text)
|
r = '<w:r><w:rPr><w:b/><w:color w:val="FFFFFF"/></w:rPr><w:t xml:space="preserve">%s</w:t></w:r>' % escape(text)
|
||||||
else:
|
else:
|
||||||
r = runs(text)
|
shd = ''; r = runs(text)
|
||||||
return ('<w:tc><w:tcPr><w:tcW w:w="0" w:type="auto"/>%s</w:tcPr><w:p>%s</w:p></w:tc>' % (shd, r))
|
return '<w:tc><w:tcPr><w:tcW w:w="0" w:type="auto"/>%s</w:tcPr><w:p>%s</w:p></w:tc>' % (shd, r)
|
||||||
|
|
||||||
def table(headers, rows):
|
def table(headers, rows):
|
||||||
borders = ('<w:tblBorders>' + ''.join(
|
borders = '<w:tblBorders>' + ''.join('<w:%s w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/>'%s
|
||||||
'<w:%s w:val="single" w:sz="4" w:space="0" w:color="BFBFBF"/>' % s
|
for s in ['top','left','bottom','right','insideH','insideV']) + '</w:tblBorders>'
|
||||||
for s in ['top','left','bottom','right','insideH','insideV']) + '</w:tblBorders>')
|
out = ['<w:tbl><w:tblPr><w:tblW w:w="5000" w:type="pct"/>%s<w:tblLook w:firstRow="1"/></w:tblPr>' % borders]
|
||||||
tblpr = '<w:tblPr><w:tblW w:w="5000" w:type="pct"/>%s<w:tblLook w:firstRow="1"/></w:tblPr>' % borders
|
|
||||||
out = ['<w:tbl>', tblpr]
|
|
||||||
out.append('<w:tr>' + ''.join(cell(h, True) for h in headers) + '</w:tr>')
|
out.append('<w:tr>' + ''.join(cell(h, True) for h in headers) + '</w:tr>')
|
||||||
for row in rows:
|
for row in rows: out.append('<w:tr>' + ''.join(cell(c) for c in row) + '</w:tr>')
|
||||||
out.append('<w:tr>' + ''.join(cell(c) for c in row) + '</w:tr>')
|
out.append('</w:tbl><w:p/>')
|
||||||
out.append('</w:tbl>')
|
|
||||||
out.append('<w:p/>') # spacing after table
|
|
||||||
return ''.join(out)
|
return ''.join(out)
|
||||||
|
|
||||||
def title_block(t, sub, meta):
|
|
||||||
return (para(t, 'Title') + para(sub, 'Subtitle') + para(meta, 'Meta'))
|
|
||||||
|
|
||||||
body = []
|
body = []
|
||||||
for b in C:
|
for b in C:
|
||||||
k = b[0]
|
k = b[0]
|
||||||
if k == 'title': body.append(title_block(b[1], b[2], b[3]))
|
if k == 'title': body.append(para(b[1],'Title')+para(b[2],'Subtitle')+para(b[3],'Meta'))
|
||||||
elif k == 'h1': body.append(para(b[1], 'Heading1'))
|
elif k in ('h1','h2','h3'): body.append(para(b[1], {'h1':'Heading1','h2':'Heading2','h3':'Heading3'}[k]))
|
||||||
elif k == 'h2': body.append(para(b[1], 'Heading2'))
|
|
||||||
elif k == 'h3': body.append(para(b[1], 'Heading3'))
|
|
||||||
elif k == 'p': body.append(para(b[1]))
|
elif k == 'p': body.append(para(b[1]))
|
||||||
elif k == 'note': body.append(para(b[1], 'Note'))
|
elif k == 'note': body.append(para(b[1],'Note'))
|
||||||
elif k == 'ul': body.append(''.join(listitem(x, 1) for x in b[1]))
|
elif k == 'ul': body.append(''.join(listitem(x,1) for x in b[1]))
|
||||||
elif k == 'ol': body.append(''.join(listitem(x, 2) for x in b[1]))
|
elif k == 'ol': body.append(''.join(listitem(x,2) for x in b[1]))
|
||||||
elif k == 'table': body.append(table(b[1], b[2]))
|
elif k == 'table': body.append(table(b[1], b[2]))
|
||||||
elif k == 'pb': body.append('<w:p><w:r><w:br w:type="page"/></w:r></w:p>')
|
elif k == 'pb': body.append('<w:p><w:r><w:br w:type="page"/></w:r></w:p>')
|
||||||
|
|
||||||
SECT = ('<w:sectPr><w:pgSz w:w="11906" w:h="16838"/>'
|
SECT = ('<w:sectPr><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0"/></w:sectPr>')
|
||||||
'<w:pgMar w:top="1417" w:right="1417" w:bottom="1417" w:left="1417" w:header="708" w:footer="708" w:gutter="0"/>'
|
|
||||||
'</w:sectPr>')
|
|
||||||
|
|
||||||
document = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
document = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||||||
'<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
|
'<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body>'
|
||||||
'<w:body>' + ''.join(body) + SECT + '</w:body></w:document>')
|
+ ''.join(body) + SECT + '</w:body></w:document>')
|
||||||
|
|
||||||
STYLES = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
STYLES = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||||||
'<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
|
'<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
|
||||||
'<w:docDefaults><w:rPrDefault><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="22"/></w:rPr></w:rPrDefault></w:docDefaults>'
|
'<w:docDefaults><w:rPrDefault><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="22"/></w:rPr></w:rPrDefault></w:docDefaults>'
|
||||||
'<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:pPr><w:spacing w:after="140" w:line="276" w:lineRule="auto"/></w:pPr></w:style>'
|
'<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:pPr><w:spacing w:after="140" w:line="276" w:lineRule="auto"/></w:pPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="Title"><w:name w:val="Title"/><w:pPr><w:spacing w:before="2400" w:after="120"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="72"/></w:rPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="Title"><w:name w:val="Title"/><w:pPr><w:spacing w:before="2600" w:after="120"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="72"/></w:rPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="Subtitle"><w:name w:val="Subtitle"/><w:pPr><w:spacing w:after="80"/></w:pPr><w:rPr><w:color w:val="2E74B5"/><w:sz w:val="36"/></w:rPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="Subtitle"><w:name w:val="Subtitle"/><w:pPr><w:spacing w:after="80"/></w:pPr><w:rPr><w:color w:val="2E74B5"/><w:sz w:val="34"/></w:rPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="Meta"><w:name w:val="Meta"/><w:rPr><w:color w:val="808080"/><w:sz w:val="20"/></w:rPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="Meta"><w:name w:val="Meta"/><w:rPr><w:color w:val="808080"/><w:sz w:val="20"/></w:rPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="320" w:after="120"/><w:outlineLvl w:val="0"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="34"/></w:rPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="360" w:after="120"/><w:pBdr><w:bottom w:val="single" w:sz="6" w:space="3" w:color="2E74B5"/></w:pBdr><w:outlineLvl w:val="0"/></w:pPr><w:rPr><w:b/><w:color w:val="1F3864"/><w:sz w:val="32"/></w:rPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="Heading2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="240" w:after="80"/><w:outlineLvl w:val="1"/></w:pPr><w:rPr><w:b/><w:color w:val="2E74B5"/><w:sz w:val="28"/></w:rPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="Heading2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="240" w:after="80"/><w:outlineLvl w:val="1"/></w:pPr><w:rPr><w:b/><w:color w:val="2E74B5"/><w:sz w:val="27"/></w:rPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="Heading3"><w:name w:val="heading 3"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="200" w:after="60"/><w:outlineLvl w:val="2"/></w:pPr><w:rPr><w:b/><w:color w:val="404040"/><w:sz w:val="24"/></w:rPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="Heading3"><w:name w:val="heading 3"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:pPr><w:keepNext/><w:spacing w:before="200" w:after="60"/><w:outlineLvl w:val="2"/></w:pPr><w:rPr><w:b/><w:color w:val="404040"/><w:sz w:val="24"/></w:rPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="ListParagraph"><w:name w:val="List Paragraph"/><w:basedOn w:val="Normal"/><w:pPr><w:ind w:left="567"/><w:spacing w:after="60"/></w:pPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="ListParagraph"><w:name w:val="List Paragraph"/><w:basedOn w:val="Normal"/><w:pPr><w:ind w:left="567"/><w:spacing w:after="60"/></w:pPr></w:style>'
|
||||||
'<w:style w:type="paragraph" w:styleId="Note"><w:name w:val="Note"/><w:basedOn w:val="Normal"/><w:pPr><w:pBdr><w:left w:val="single" w:sz="18" w:space="6" w:color="F59E0B"/></w:pBdr><w:ind w:left="227"/><w:spacing w:before="120" w:after="120"/><w:shd w:val="clear" w:fill="FFFBEB"/></w:pPr><w:rPr><w:i/><w:color w:val="7A5B00"/></w:rPr></w:style>'
|
'<w:style w:type="paragraph" w:styleId="Note"><w:name w:val="Note"/><w:basedOn w:val="Normal"/><w:pPr><w:pBdr><w:left w:val="single" w:sz="18" w:space="6" w:color="F59E0B"/></w:pBdr><w:ind w:left="227"/><w:spacing w:before="120" w:after="120"/><w:shd w:val="clear" w:fill="FFFBEB"/></w:pPr><w:rPr><w:i/><w:color w:val="7A5B00"/></w:rPr></w:style>'
|
||||||
@@ -359,49 +286,35 @@ NUMBERING = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
|||||||
'<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
|
'<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">'
|
||||||
'<w:abstractNum w:abstractNumId="0"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val="•"/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="567" w:hanging="284"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl></w:abstractNum>'
|
'<w:abstractNum w:abstractNumId="0"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val="•"/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="567" w:hanging="284"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:hAnsi="Symbol" w:hint="default"/></w:rPr></w:lvl></w:abstractNum>'
|
||||||
'<w:abstractNum w:abstractNumId="1"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="decimal"/><w:lvlText w:val="%1."/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="567" w:hanging="284"/></w:pPr></w:lvl></w:abstractNum>'
|
'<w:abstractNum w:abstractNumId="1"><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="decimal"/><w:lvlText w:val="%1."/><w:lvlJc w:val="left"/><w:pPr><w:ind w:left="567" w:hanging="284"/></w:pPr></w:lvl></w:abstractNum>'
|
||||||
'<w:num w:numId="1"><w:abstractNumId w:val="0"/></w:num>'
|
'<w:num w:numId="1"><w:abstractNumId w:val="0"/></w:num><w:num w:numId="2"><w:abstractNumId w:val="1"/></w:num></w:numbering>')
|
||||||
'<w:num w:numId="2"><w:abstractNumId w:val="1"/></w:num>'
|
|
||||||
'</w:numbering>')
|
|
||||||
|
|
||||||
CONTENT_TYPES = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
CT = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||||||
'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
|
'<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'
|
||||||
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
|
'<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>'
|
||||||
'<Default Extension="xml" ContentType="application/xml"/>'
|
'<Default Extension="xml" ContentType="application/xml"/>'
|
||||||
'<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>'
|
'<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>'
|
||||||
'<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>'
|
'<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>'
|
||||||
'<Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/>'
|
'<Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/>'
|
||||||
'<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>'
|
'<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>')
|
||||||
'</Types>')
|
|
||||||
|
|
||||||
RELS = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
RELS = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||||||
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
|
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
|
||||||
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>'
|
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>'
|
||||||
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>'
|
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/></Relationships>')
|
||||||
'</Relationships>')
|
DRELS = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||||||
|
|
||||||
DOC_RELS = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
|
||||||
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
|
'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
|
||||||
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'
|
'<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'
|
||||||
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/>'
|
'<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/></Relationships>')
|
||||||
'</Relationships>')
|
|
||||||
|
|
||||||
CORE = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
CORE = ('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
||||||
'<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" '
|
'<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
||||||
'xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
|
'<dc:title>Manuale d\'uso NIS2 Agile</dc:title><dc:creator>NIS2 Agile</dc:creator><cp:lastModifiedBy>NIS2 Agile</cp:lastModifiedBy>'
|
||||||
'<dc:title>Manuale d\'uso NIS2 Agile</dc:title><dc:creator>NIS2 Agile</dc:creator>'
|
'<dcterms:created xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:created><dcterms:modified xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:modified></cp:coreProperties>')
|
||||||
'<cp:lastModifiedBy>NIS2 Agile</cp:lastModifiedBy>'
|
|
||||||
'<dcterms:created xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:created>'
|
|
||||||
'<dcterms:modified xsi:type="dcterms:W3CDTF">2026-06-11T00:00:00Z</dcterms:modified>'
|
|
||||||
'</cp:coreProperties>')
|
|
||||||
|
|
||||||
with zipfile.ZipFile(OUT, 'w', zipfile.ZIP_DEFLATED) as z:
|
with zipfile.ZipFile(OUT, 'w', zipfile.ZIP_DEFLATED) as z:
|
||||||
z.writestr('[Content_Types].xml', CONTENT_TYPES)
|
z.writestr('[Content_Types].xml', CT)
|
||||||
z.writestr('_rels/.rels', RELS)
|
z.writestr('_rels/.rels', RELS)
|
||||||
z.writestr('word/document.xml', document)
|
z.writestr('word/document.xml', document)
|
||||||
z.writestr('word/styles.xml', STYLES)
|
z.writestr('word/styles.xml', STYLES)
|
||||||
z.writestr('word/numbering.xml', NUMBERING)
|
z.writestr('word/numbering.xml', NUMBERING)
|
||||||
z.writestr('word/_rels/document.xml.rels', DOC_RELS)
|
z.writestr('word/_rels/document.xml.rels', DRELS)
|
||||||
z.writestr('docProps/core.xml', CORE)
|
z.writestr('docProps/core.xml', CORE)
|
||||||
|
print("OK ->", OUT, "| blocchi:", len(C))
|
||||||
print("OK ->", OUT)
|
|
||||||
print("blocchi:", len(C))
|
|
||||||
|
|||||||
Reference in New Issue
Block a user