diff --git a/app/routers/audit_full.py b/app/routers/audit_full.py index 83164fc..a71c262 100644 --- a/app/routers/audit_full.py +++ b/app/routers/audit_full.py @@ -1,7 +1,7 @@ """Router Audit Complet — import JSON, liste, detail, carte flux, carte applicative""" import json from fastapi import APIRouter, Request, Depends, UploadFile, File -from fastapi.responses import HTMLResponse, RedirectResponse +from fastapi.responses import HTMLResponse, RedirectResponse, StreamingResponse from fastapi.templating import Jinja2Templates from sqlalchemy import text from ..dependencies import get_db, get_current_user, get_user_perms, can_view, base_context @@ -192,6 +192,80 @@ async def audit_full_import(request: Request, db=Depends(get_db), ) +@router.get("/audit-full/export-csv") +async def audit_full_export_csv(request: Request, db=Depends(get_db)): + user = get_current_user(request) + if not user: + return RedirectResponse(url="/login") + + import io, csv + filtre = request.query_params.get("filter", "") + search = request.query_params.get("q", "").strip() + domain = request.query_params.get("domain", "") + + audits = get_latest_audits(db, limit=9999) + + # Memes filtres que la page liste + if filtre == "reboot": + audits = [a for a in audits if a.reboot_required] + elif filtre == "uptime": + audits = [a for a in audits if a.uptime and ("month" in a.uptime or "year" in a.uptime)] + elif filtre and filtre.startswith("app_"): + app_patterns = { + "app_postgres": "postgres", "app_mariadb": "mariadb|mysqld", + "app_hana": "hdb|sapstart|HANA", "app_oracle": "ora_pmon|oracle", + "app_httpd": "httpd", "app_nginx": "nginx", "app_haproxy": "haproxy", + "app_tomcat": "tomcat|catalina", "app_nodejs": "node", + "app_redis": "redis", "app_mongodb": "mongod", + "app_elastic": "elasticsearch|opensearch", "app_container": "docker|podman", + "app_java": "java|\\.jar", + } + pattern = app_patterns.get(filtre, "") + if pattern: + ids = {r.id for r in db.execute(text(""" + SELECT id FROM server_audit_full + WHERE status = 'ok' + AND (services::text ~* :pat OR listen_ports::text ~* :pat OR processes::text ~* :pat) + AND id IN (SELECT DISTINCT ON (hostname) id FROM server_audit_full WHERE status = 'ok' ORDER BY hostname, audit_date DESC) + """), {"pat": pattern}).fetchall()} + audits = [a for a in audits if a.id in ids] + if domain: + zone_servers = {r.hostname for r in db.execute(text( + "SELECT s.hostname FROM servers s JOIN zones z ON s.zone_id = z.id WHERE z.name = :name" + ), {"name": domain}).fetchall()} + if zone_servers: + audits = [a for a in audits if a.hostname in zone_servers] + else: + domain_servers = {r.hostname for r in db.execute(text(""" + SELECT s.hostname FROM servers s JOIN domain_environments de ON s.domain_env_id = de.id + JOIN domains d ON de.domain_id = d.id WHERE d.code = :dc + """), {"dc": domain}).fetchall()} + audits = [a for a in audits if a.hostname in domain_servers] + if search: + q = search.lower() + audits = [a for a in audits if q in a.hostname.lower()] + + # Generer CSV + output = io.StringIO() + writer = csv.writer(output, delimiter=";") + writer.writerow(["Hostname", "OS", "Kernel", "Uptime", "Services", "Processus", + "Ports", "Connexions", "Reboot requis", "Date audit"]) + for a in audits: + writer.writerow([ + a.hostname, a.os_release or "", a.kernel or "", a.uptime or "", + a.svc_count, a.proc_count, a.port_count, a.conn_count, + "Oui" if a.reboot_required else "Non", + a.audit_date.strftime("%Y-%m-%d %H:%M") if a.audit_date else "", + ]) + + output.seek(0) + return StreamingResponse( + iter(["\ufeff" + output.getvalue()]), + media_type="text/csv", + headers={"Content-Disposition": "attachment; filename=audit_serveurs.csv"}, + ) + + @router.get("/audit-full/flow-map", response_class=HTMLResponse) async def audit_full_flow_map(request: Request, db=Depends(get_db)): user = get_current_user(request) diff --git a/app/templates/audit_full_list.html b/app/templates/audit_full_list.html index d157ff7..ac2f476 100644 --- a/app/templates/audit_full_list.html +++ b/app/templates/audit_full_list.html @@ -11,6 +11,7 @@ + Exporter CSV Carte flux