From 488b5a980b2a3af4a572cf0246f09129a4895ed7 Mon Sep 17 00:00:00 2001 From: Admin MPCZ Date: Mon, 4 May 2026 13:12:09 +0200 Subject: [PATCH] feat(patching/import): ajout colonnes Resp Domaine DTS, Referent technique, Mode operatoire, Impacts, BDD - support nouveau format S07+ + Date au lieu de Jour --- app/routers/planning_import.py | 67 ++++++++++++++++++++---------- app/templates/patching_import.html | 14 ++++++- migrate_planning_imports_v2.sql | 12 ++++++ 3 files changed, 70 insertions(+), 23 deletions(-) create mode 100644 migrate_planning_imports_v2.sql diff --git a/app/routers/planning_import.py b/app/routers/planning_import.py index 76f2b52..7883ef2 100644 --- a/app/routers/planning_import.py +++ b/app/routers/planning_import.py @@ -23,24 +23,31 @@ from ..config import APP_NAME router = APIRouter() templates = Jinja2Templates(directory="app/templates") -# Colonnes attendues dans les feuilles Sxx (ordre indicatif, on matche par regex/lower) +# Colonnes attendues dans les feuilles Sxx (ordre = priorité, on matche par regex/lower) +# Le fichier 2026 a 12 variantes d'en-têtes selon la semaine +# (ancien format S02-S06, nouveau format DTS S07+) KNOWN_COLUMNS = { - "asset_name": [r"asset\s*name", r"\bnom\b"], - "intervenant": [r"intervenant"], - "environnement": [r"environnement|environement"], - "domaine": [r"^domaine"], - "os": [r"^\s*os\s*$"], - "os_version": [r"version\s*os"], - "application_name": [r"application", r"logiciel"], - "valideur_ra": [r"valideur"], - "description": [r"description"], - "assistant": [r"^assistant"], - "commentaire": [r"commentaire|impact"], - "duree_coupure": [r"dur.+coupure"], - "jour": [r"^\s*jour\s*$|date\s*pr.+vis"], - "heure": [r"^\s*heure"], - "pb_espace_disque": [r"espace\s*disque"], - "date_patch_realise":[r"date\s*du?\s*patch.+r.+alis"], + "asset_name": [r"asset\s*name", r"\bnom\b"], + "intervenant": [r"intervenant"], + "environnement": [r"environnement|environement"], + "domaine": [r"^domaine"], + "os": [r"^\s*os\s*$"], + "os_version": [r"version\s*os"], # matche "Version OS" et "Version OS->Nom" + "application_name": [r"logiciel", r"application", r"^nom\s*complet$"], + "valideur_ra": [r"valideur"], + "responsable_domaine_dts":[r"responsable\s*domaine"], + "description": [r"description"], + "assistant": [r"^assistant"], + "referent_technique": [r"r.f.rent\s*tech"], + "mode_operatoire": [r"mode\s*op.ratoire"], + "impacts": [r"^impact"], + "commentaire": [r"commentaire"], + "base_de_donnees": [r"base\s*de\s*donn"], + "duree_coupure": [r"dur.+coupure"], + "jour": [r"^\s*jour\s*$", r"^\s*date\s*$", r"date\s*pr.+vis"], + "heure": [r"^\s*heure"], + "pb_espace_disque": [r"espace\s*disque"], + "date_patch_realise": [r"date\s*du?\s*patch.+r.+alis"], } SHEET_WEEK_RE = re.compile(r"^S\s*0?(\d+)$", re.IGNORECASE) @@ -228,9 +235,11 @@ async def import_sheet_json(request: Request, import_id: int, sheet_name: str, rows = db.execute(text(""" SELECT r.id, r.row_index, r.asset_name, r.intervenant, r.environnement, - r.domaine, r.os, r.os_version, r.application_name, r.valideur_ra, - r.description, r.assistant, r.commentaire, r.duree_coupure, - r.jour, r.heure, r.pb_espace_disque, r.date_patch_realise, + r.domaine, r.os, r.os_version, r.application_name, + r.valideur_ra, r.responsable_domaine_dts, + r.description, r.assistant, r.referent_technique, + r.mode_operatoire, r.impacts, r.commentaire, r.base_de_donnees, + r.duree_coupure, r.jour, r.heure, r.pb_espace_disque, r.date_patch_realise, r.server_id, s.hostname as resolved_hostname FROM patch_planning_import_rows r LEFT JOIN servers s ON s.id = r.server_id @@ -251,9 +260,14 @@ async def import_sheet_json(request: Request, import_id: int, sheet_name: str, "os_version": r.os_version, "application_name": r.application_name, "valideur_ra": r.valideur_ra, + "responsable_domaine_dts": r.responsable_domaine_dts, "description": r.description, "assistant": r.assistant, + "referent_technique": r.referent_technique, + "mode_operatoire": r.mode_operatoire, + "impacts": r.impacts, "commentaire": r.commentaire, + "base_de_donnees": r.base_de_donnees, "duree_coupure": r.duree_coupure, "jour": r.jour.isoformat() if r.jour else None, "heure": r.heure, @@ -338,13 +352,17 @@ async def import_upload(request: Request, db=Depends(get_db), INSERT INTO patch_planning_import_rows ( import_id, sheet_name, week_number, row_index, asset_name, intervenant, environnement, domaine, os, os_version, - application_name, valideur_ra, description, assistant, commentaire, + application_name, valideur_ra, responsable_domaine_dts, + description, assistant, referent_technique, mode_operatoire, impacts, + commentaire, base_de_donnees, duree_coupure, jour, heure, pb_espace_disque, date_patch_realise, raw_data, server_id ) VALUES ( :imp, :sn, :wn, :ri, :an, :it, :en, :do, :os, :ov, - :ap, :vr, :de, :as_, :co, + :ap, :vr, :rd, + :de, :as_, :rt, :mo, :im, + :co, :bdd, :dc, :jr, :hr, :pb, :dpr, :raw, :sid ) @@ -358,9 +376,14 @@ async def import_upload(request: Request, db=Depends(get_db), "ov": str(rec.get("os_version")) if rec.get("os_version") else None, "ap": str(rec.get("application_name")) if rec.get("application_name") else None, "vr": str(rec.get("valideur_ra")) if rec.get("valideur_ra") else None, + "rd": str(rec.get("responsable_domaine_dts")) if rec.get("responsable_domaine_dts") else None, "de": str(rec.get("description")) if rec.get("description") else None, "as_": str(rec.get("assistant")) if rec.get("assistant") else None, + "rt": str(rec.get("referent_technique")) if rec.get("referent_technique") else None, + "mo": str(rec.get("mode_operatoire")) if rec.get("mode_operatoire") else None, + "im": str(rec.get("impacts")) if rec.get("impacts") else None, "co": str(rec.get("commentaire")) if rec.get("commentaire") else None, + "bdd": str(rec.get("base_de_donnees")) if rec.get("base_de_donnees") else None, "dc": str(rec.get("duree_coupure")) if rec.get("duree_coupure") else None, "jr": _coerce_date(rec.get("jour")), "hr": str(rec.get("heure")) if rec.get("heure") else None, diff --git a/app/templates/patching_import.html b/app/templates/patching_import.html index be93609..81a2363 100644 --- a/app/templates/patching_import.html +++ b/app/templates/patching_import.html @@ -137,10 +137,16 @@ Env Domaine OS + Version OS Application Intervenant Valideur RA - Jour + Resp. Domaine DTS + Référent tech. + Mode op. + Impacts + BDD + Date Heure Coupure Pb disque @@ -246,9 +252,15 @@ + '' + escapeHTML(r.environnement||'') + '' + '' + escapeHTML(r.domaine||'') + '' + '' + escapeHTML(r.os||'') + '' + + '' + escapeHTML(r.os_version||'') + '' + '' + escapeHTML(r.application_name||'') + '' + '' + escapeHTML(r.intervenant||'') + '' + '' + escapeHTML(r.valideur_ra||'') + '' + + '' + escapeHTML(r.responsable_domaine_dts||'') + '' + + '' + escapeHTML(r.referent_technique||'') + '' + + '' + escapeHTML(r.mode_operatoire||'') + '' + + '' + escapeHTML(r.impacts||'') + '' + + '' + escapeHTML(r.base_de_donnees||'') + '' + '' + escapeHTML(r.jour||'') + '' + '' + escapeHTML(r.heure||'') + '' + '' + escapeHTML(r.duree_coupure||'') + '' diff --git a/migrate_planning_imports_v2.sql b/migrate_planning_imports_v2.sql new file mode 100644 index 0000000..05fe84f --- /dev/null +++ b/migrate_planning_imports_v2.sql @@ -0,0 +1,12 @@ +-- Migration v2 : ajout des colonnes manquantes dans patch_planning_import_rows +-- (variations d'en-têtes selon semaines : nouveau format DTS introduit en cours d'année) +-- Idempotent + +ALTER TABLE public.patch_planning_import_rows + ADD COLUMN IF NOT EXISTS responsable_domaine_dts text, + ADD COLUMN IF NOT EXISTS referent_technique text, + ADD COLUMN IF NOT EXISTS mode_operatoire text, + ADD COLUMN IF NOT EXISTS impacts text, + ADD COLUMN IF NOT EXISTS base_de_donnees text; + +-- Pas de nouveau GRANT nécessaire (la table est déjà accessible à patchcenter)