Files
TDI-Dashboard/Tool/queries/documenti.py
T
Luca Banfi e9d07162d9
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline failed
lint syntax fixes
2026-05-18 16:25:52 +02:00

135 lines
5.2 KiB
Python

"""queries/documenti.py — sessione_documenti con join sessione"""
from .db import query, e, dt
_STATUS_BADGE = {
'trovato': '<span class="badge doc-trovato">trovato</span>',
'caricato': '<span class="badge doc-caricato">caricato</span>',
'errore': '<span class="badge doc-errore">errore</span>',
'warning': '<span class="badge doc-warning">warning</span>',
}
def get_documenti(db_path: str) -> list:
sql = """
SELECT
sd.sessione_id,
s.corso,
s.azienda,
sd.subfolder,
sd.doc_type,
sd.doc_status,
sd.filename,
sd.note,
sd.sp_web_url,
sd.uploaded_at
FROM sessione_documenti sd
LEFT JOIN sessione s ON s.id = sd.sessione_id
ORDER BY sd.sessione_id, sd.subfolder, sd.filename
"""
return query(db_path, sql)
def get_stats(db_path: str) -> dict:
rows = get_documenti(db_path)
return {
'doc_trovato': sum(1 for r in rows if r['doc_status'] == 'trovato'),
'doc_caricato': sum(1 for r in rows if r['doc_status'] == 'caricato'),
'doc_errore': sum(1 for r in rows if r['doc_status'] == 'errore'),
'doc_sessioni': len({r['sessione_id'] for r in rows}),
}
def render_page(rows: list) -> str:
if not rows:
return '<p class="empty-msg">Nessun documento registrato.</p>'
# Group by sessione_id
sessions: dict = {}
order: list = []
for r in rows:
sid = r['sessione_id']
if sid not in sessions:
sessions[sid] = {'corso': r['corso'], 'azienda': r['azienda'], 'docs': []}
order.append(sid)
sessions[sid]['docs'].append(r)
html_parts = []
for sid in order:
s = sessions[sid]
docs = s['docs']
n_trovato = sum(1 for d in docs if d['doc_status'] == 'trovato')
n_caricato = sum(1 for d in docs if d['doc_status'] == 'caricato')
n_errore = sum(1 for d in docs if d['doc_status'] == 'errore')
n_warning = sum(1 for d in docs if d['doc_status'] == 'warning')
counts_html = (
(f'<span class="cnt cnt-caricato">{n_caricato} caricati</span>' if n_caricato else '')
+ (f'<span class="cnt cnt-trovato">{n_trovato} trovati</span>' if n_trovato else '')
+ (f'<span class="cnt cnt-warning">{n_warning} warning</span>' if n_warning else '')
+ (f'<span class="cnt cnt-errore">{n_errore} errori</span>' if n_errore else '')
)
tbody_rows = ''
for d in docs:
status = d['doc_status'] or ''
badge_html = _STATUS_BADGE.get(status, f'<span class="badge">{e(status)}</span>')
if d['sp_web_url']:
sp_cell = (
f'<a href="{e(d["sp_web_url"])}" target="_blank" rel="noopener"'
f' class="sp-link" title="Apri su SharePoint">🔗</a>'
)
else:
sp_cell = '<span class="sp-missing" title="Non caricato su SharePoint">❌</span>'
fn = d["filename"]
if fn and fn.startswith("[") and fn.endswith("]"):
fn_cell = f'<span style=\'color:#f97316;\'>{e(fn)}</span>'
else:
fn_cell = e(fn)
tbody_rows += (
f'<tr class="doc-row doc-{e(status)}"'
f' data-filename="{e(d["filename"] or "")}"'
f' data-doctype="{e(d["doc_type"] or "")}"'
f' data-subfolder="{e(d["subfolder"] or "")}"'
f' data-status="{e(status)}"'
f' data-note="{e(d["note"] or "")}"'
f' data-uploaded="{e(dt(d["uploaded_at"]) if status == "caricato" else "")}">'
f'<td class="col-filename" title="{e(d["filename"] or "")}">{fn_cell}</td>'
f'<td class="col-doctype">{e(d["doc_type"])}</td>'
f'<td class="col-subfolder">{e(d["subfolder"])}</td>'
f'<td class="col-status">{badge_html}</td>'
f'<td class="col-sp">{sp_cell}</td>'
f'<td class="col-note">{e(d["note"])}</td>'
f'<td class="col-uploaded">{dt(d["uploaded_at"]) if status == "caricato" else "-"}</td>'
f'</tr>'
)
subtable = (
'<table class="doc-subtable">'
'<thead><tr>'
'<th>File</th><th>Tipo</th><th>Cartella</th>'
'<th>Stato</th><th>SP</th><th>Note</th><th>Caricato</th>'
'</tr></thead>'
f'<tbody>{tbody_rows}</tbody>'
'</table>'
)
open_attr = ' open' if (n_errore > 0 or n_warning > 0) else ''
html_parts.append(
f'<details class="sess-block"{open_attr}'
f' data-sessione="{e(sid)}"'
f' data-corso="{e(s["corso"])}"'
f' data-azienda="{e(s["azienda"])}">'
f'<summary class="sess-summary">'
f'<span class="sess-id">#{e(sid)}</span>'
f'<span class="sess-corso">{e(s["corso"])}</span>'
f'<span class="sess-azienda">{e(s["azienda"])}</span>'
f'<span class="sess-counts">{counts_html}</span>'
f'</summary>'
f'<div class="sess-docs">{subtable}</div>'
f'</details>'
)
return '\n'.join(html_parts)