diff --git a/app/routers/servers.py b/app/routers/servers.py index 5577166..fff6723 100644 --- a/app/routers/servers.py +++ b/app/routers/servers.py @@ -239,41 +239,65 @@ async def servers_bulk(request: Request, db=Depends(get_db), from sqlalchemy import text as sqlt + bulk_value_clean = (bulk_value or "").strip() + n_updated = 0 + if bulk_field in ("tier", "etat", "patch_os_owner", "licence_support"): - db.execute(sqlt(f"UPDATE servers SET {bulk_field} = :val WHERE id = ANY(:ids)"), - {"val": bulk_value, "ids": ids}) + res = db.execute(sqlt(f"UPDATE servers SET {bulk_field} = :val WHERE id = ANY(:ids)"), + {"val": bulk_value_clean, "ids": ids}) + n_updated = res.rowcount or 0 elif bulk_field == "domain_code": - # Trouver le domain_env_id correspondant (prod par defaut) + # Tous les serveurs prennent le 1er domain_env de ce domaine + # (priorité Production > autres via display_order) row = db.execute(sqlt(""" SELECT de.id FROM domain_environments de JOIN domains d ON de.domain_id = d.id JOIN environments e ON de.environment_id = e.id - WHERE d.code = :dc ORDER BY e.display_order LIMIT 1 - """), {"dc": bulk_value}).fetchone() + WHERE LOWER(d.code) = LOWER(:dc) ORDER BY e.display_order LIMIT 1 + """), {"dc": bulk_value_clean}).fetchone() if row: - db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = ANY(:ids)"), - {"deid": row.id, "ids": ids}) + res = db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = ANY(:ids)"), + {"deid": row.id, "ids": ids}) + n_updated = res.rowcount or 0 + else: + logger.warning(f"servers_bulk domain_code: aucun domain_environments pour {bulk_value_clean!r}") elif bulk_field == "env_code": - # Pour chaque serveur, garder son domaine mais changer l'env + # Pour chaque serveur, garder son domaine actuel et changer l'env. + # Si serveur sans domain_env_id, fallback : 1er domain dispo + cet env. for sid in ids: srv = db.execute(sqlt(""" - SELECT d.id as did FROM servers s - JOIN domain_environments de ON s.domain_env_id = de.id - JOIN domains d ON de.domain_id = d.id + SELECT s.id, s.domain_env_id, de.domain_id AS did + FROM servers s + LEFT JOIN domain_environments de ON s.domain_env_id = de.id WHERE s.id = :sid """), {"sid": sid}).fetchone() - if srv: + if not srv: + continue + did = srv.did # peut être None si serveur sans domaine + if did: de = db.execute(sqlt(""" SELECT de.id FROM domain_environments de JOIN environments e ON de.environment_id = e.id - WHERE de.domain_id = :did AND e.code = :ec - """), {"did": srv.did, "ec": bulk_value}).fetchone() - if de: - db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = :sid"), - {"deid": de.id, "sid": sid}) + WHERE de.domain_id = :did AND LOWER(e.code) = LOWER(:ec) + """), {"did": did, "ec": bulk_value_clean}).fetchone() + else: + # Fallback : on prend n'importe quel domain_env avec cet env + de = db.execute(sqlt(""" + SELECT de.id FROM domain_environments de + JOIN environments e ON de.environment_id = e.id + WHERE LOWER(e.code) = LOWER(:ec) + ORDER BY de.id LIMIT 1 + """), {"ec": bulk_value_clean}).fetchone() + if de: + db.execute(sqlt("UPDATE servers SET domain_env_id = :deid WHERE id = :sid"), + {"deid": de.id, "sid": sid}) + n_updated += 1 + else: + logger.warning(f"servers_bulk env_code: pas de domain_env pour env {bulk_value_clean!r} (sid={sid}, did={did})") db.commit() - return RedirectResponse(url=f"/servers?msg=bulk_{len(ids)}", status_code=303) + logger.info(f"servers_bulk: field={bulk_field} value={bulk_value_clean!r} ids={len(ids)} updated={n_updated}") + return RedirectResponse(url=f"/servers?msg=bulk_{n_updated}", status_code=303) @router.post("/servers/{server_id}/sync-qualys", response_class=HTMLResponse) diff --git a/app/services/server_service.py b/app/services/server_service.py index eb11af3..c002845 100644 --- a/app/services/server_service.py +++ b/app/services/server_service.py @@ -208,25 +208,39 @@ def list_servers(db, filters, page=1, per_page=50, sort="hostname", sort_dir="as def update_server(db, server_id, data, username): - """Met a jour un serveur et log l'action""" + """Met a jour un serveur et log l'action. + Comparaisons code domain/env/zone en case-insensitive (la BD mixte + 'RECETTE'/'Recette'/'recette' n'a pas une casse cohérente).""" + import logging + log = logging.getLogger("patchcenter.server") + # Domain + Env -> domain_env_id - if data.get("domain_code") and data.get("env_code"): + dc = (data.get("domain_code") or "").strip() + ec = (data.get("env_code") or "").strip() + if dc and ec: row = db.execute(text(""" SELECT de.id FROM domain_environments de JOIN domains d ON de.domain_id = d.id JOIN environments e ON de.environment_id = e.id - WHERE d.code = :dc AND e.code = :ec - """), {"dc": data["domain_code"], "ec": data["env_code"]}).fetchone() + WHERE LOWER(d.code) = LOWER(:dc) AND LOWER(e.code) = LOWER(:ec) + """), {"dc": dc, "ec": ec}).fetchone() if row: db.execute(text("UPDATE servers SET domain_env_id = :deid WHERE id = :id"), {"deid": row.id, "id": server_id}) + else: + log.warning(f"update_server({server_id}): pas de domain_environments pour ({dc!r}, {ec!r})") - # Zone - if data.get("zone"): - zrow = db.execute(text("SELECT id FROM zones WHERE name = :z"), {"z": data["zone"]}).fetchone() + # Zone (case-insensitive sur name) + zn = (data.get("zone") or "").strip() + if zn: + zrow = db.execute(text( + "SELECT id FROM zones WHERE LOWER(name) = LOWER(:z)" + ), {"z": zn}).fetchone() if zrow: db.execute(text("UPDATE servers SET zone_id = :zid WHERE id = :id"), {"zid": zrow.id, "id": server_id}) + else: + log.warning(f"update_server({server_id}): zone {zn!r} introuvable") # IPs (reelle + connexion) update_server_ips(db, server_id, data.get("ip_reelle"), data.get("ip_connexion"))