Qualys: - Recherche API temps réel + cache 24h base locale - Tags: liste DYN/STAT, mapping V3 (DOM-*, TYP-*, APP-*), nb assets cliquable - CRUD tags: créer STAT, supprimer, resync API - Détail asset: infos + décodage nomenclature V3 + tags assignés - Ajout/retrait tag unitaire avec autocomplete filtrable - Bulk add/remove tag en masse avec dropdown filtrable - Tags retirer: charge dynamiquement les STAT assignés aux assets sélectionnés - Resync assets sélectionnés + retour même recherche Contacts: - 50 contacts importés avec 93 scopes (domaine/app/serveur/zone par env) - 13 rôles (responsable_domaine, ra_prod, ra_recette, referent_technique...) - Recherche par nom/email/serveur (affiche contacts liés) - CRUD complet: éditer, scopes, activer/désactiver, supprimer - Serveurs liés calculés dynamiquement depuis les scopes Audit: - Restructuré: Audit général + sous-menu Spécifique - Dernier audit global affiché avec date - Lancer audit général avec exclusions (domaines/zones) et parallélisme - KPIs Qualys KO et S1 KO cliquables - Export CSV Serveurs: - Actions groupées bulk (domaine, env, tier, état, owner, licence) - Dashboard: KPI EOL ajouté - Filtre état: EOL + en décommissionnement ajoutés - 138 serveurs EOL importés depuis Qualys (owner=na, hors périmètre) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 lines
3.0 KiB
Python
88 lines
3.0 KiB
Python
"""PatchCenter v2 — Entry point FastAPI"""
|
|
from fastapi import FastAPI, Request
|
|
from fastapi.responses import RedirectResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
from .config import APP_NAME, APP_VERSION
|
|
from .dependencies import get_current_user, get_user_perms
|
|
from .database import SessionLocal
|
|
from .routers import auth, dashboard, servers, settings, users, campaigns, planning, specifics, audit, contacts, qualys
|
|
|
|
|
|
class PermissionsMiddleware(BaseHTTPMiddleware):
|
|
"""Injecte user + perms dans request.state pour tous les templates"""
|
|
async def dispatch(self, request: Request, call_next):
|
|
user = get_current_user(request)
|
|
perms = {}
|
|
if user:
|
|
db = SessionLocal()
|
|
try:
|
|
perms = get_user_perms(db, user)
|
|
finally:
|
|
db.close()
|
|
request.state.user = user
|
|
request.state.perms = perms
|
|
response = await call_next(request)
|
|
return response
|
|
|
|
|
|
app = FastAPI(title=APP_NAME, version=APP_VERSION)
|
|
app.add_middleware(PermissionsMiddleware)
|
|
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
|
|
|
app.include_router(auth.router)
|
|
app.include_router(dashboard.router)
|
|
app.include_router(servers.router)
|
|
app.include_router(settings.router)
|
|
app.include_router(users.router)
|
|
app.include_router(campaigns.router)
|
|
app.include_router(planning.router)
|
|
app.include_router(specifics.router)
|
|
app.include_router(audit.router)
|
|
app.include_router(contacts.router)
|
|
app.include_router(qualys.router)
|
|
|
|
|
|
@app.get("/")
|
|
async def root(request: Request):
|
|
user = get_current_user(request)
|
|
if user:
|
|
return RedirectResponse(url="/dashboard")
|
|
return RedirectResponse(url="/login")
|
|
|
|
|
|
@app.get("/health")
|
|
async def health():
|
|
return {"status": "ok", "app": APP_NAME, "version": APP_VERSION}
|
|
|
|
|
|
# --- Error handlers ---
|
|
from fastapi.templating import Jinja2Templates
|
|
_error_templates = Jinja2Templates(directory="app/templates")
|
|
|
|
@app.exception_handler(500)
|
|
async def internal_error(request: Request, exc):
|
|
return _error_templates.TemplateResponse("error.html", {
|
|
"request": request, "code": 500,
|
|
"title": "Application en maintenance",
|
|
"message": "Une erreur interne est survenue. L'équipe technique a été notifiée.",
|
|
}, status_code=500)
|
|
|
|
@app.exception_handler(404)
|
|
async def not_found(request: Request, exc):
|
|
return _error_templates.TemplateResponse("error.html", {
|
|
"request": request, "code": 404,
|
|
"title": "Page introuvable",
|
|
"message": "La page demandée n'existe pas.",
|
|
}, status_code=404)
|
|
|
|
@app.exception_handler(Exception)
|
|
async def generic_error(request: Request, exc):
|
|
import traceback
|
|
traceback.print_exc()
|
|
return _error_templates.TemplateResponse("error.html", {
|
|
"request": request, "code": 500,
|
|
"title": "Application en maintenance",
|
|
"message": "Une erreur interne est survenue. L'équipe technique a été notifiée.",
|
|
}, status_code=500)
|