refactor: supprime le code mort et unifie les routes de tags
Code sans aucun appelant, retiré : DatabaseService.get_revenus_summary (annoté list[dict] alors qu'il retournait un dict), get_depenses_summary, get_tag_by_id et storage.file_exists. Les tags étaient gérés à deux adresses : /api/tags (lecture, appelée par trois composants) et /api/config/tags (lecture, création, renommage, appelée par la seule page de configuration). Tout est regroupé sur /api/tags, dans le module qui leur est dédié ; config.py ne garde que les settings et ConfigPage est recâblée. Ces routes n'avaient aucun test : sept en couvrent maintenant la création, le renommage, l'unicité et les noms vides. /api/stats disparaît également : sous-ensemble de /api/dashboard/stats, il n'était appelé par personne. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,8 +4,7 @@ from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...database import DatabaseService, get_session
|
||||
from ...database.models import Tag
|
||||
from ...database import get_session
|
||||
from ...services.settings_service import (
|
||||
SETTINGS_REGISTRY,
|
||||
delete_setting,
|
||||
@@ -25,14 +24,6 @@ class SettingUpdate(BaseModel):
|
||||
value: str
|
||||
|
||||
|
||||
class TagCreate(BaseModel):
|
||||
nom: str
|
||||
|
||||
|
||||
class TagUpdate(BaseModel):
|
||||
nom: str
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Settings endpoints
|
||||
# ============================================================
|
||||
@@ -71,64 +62,3 @@ async def reset_setting(
|
||||
# Return the resolved value after deletion
|
||||
all_settings = get_all_settings(session)
|
||||
return all_settings[key]
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Tags endpoints
|
||||
# ============================================================
|
||||
|
||||
|
||||
@router.get("/tags")
|
||||
async def list_tags(
|
||||
session: Session = Depends(get_session),
|
||||
) -> list[dict]:
|
||||
"""Liste tous les tags."""
|
||||
db_service = DatabaseService(session)
|
||||
tags = db_service.list_tags()
|
||||
return [{"id": tag.id, "nom": tag.nom} for tag in tags]
|
||||
|
||||
|
||||
@router.post("/tags", status_code=201)
|
||||
async def create_tag(
|
||||
body: TagCreate,
|
||||
session: Session = Depends(get_session),
|
||||
) -> dict:
|
||||
"""Crée un nouveau tag (validation unicité)."""
|
||||
nom = body.nom.strip()
|
||||
if not nom:
|
||||
raise HTTPException(status_code=400, detail="Le nom du tag ne peut pas être vide.")
|
||||
|
||||
existing = session.query(Tag).filter(Tag.nom == nom).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=409, detail=f"Le tag '{nom}' existe déjà.")
|
||||
|
||||
tag = Tag(nom=nom)
|
||||
session.add(tag)
|
||||
session.commit()
|
||||
session.refresh(tag)
|
||||
return {"id": tag.id, "nom": tag.nom}
|
||||
|
||||
|
||||
@router.put("/tags/{tag_id}")
|
||||
async def rename_tag(
|
||||
tag_id: int,
|
||||
body: TagUpdate,
|
||||
session: Session = Depends(get_session),
|
||||
) -> dict:
|
||||
"""Renomme un tag (validation unicité)."""
|
||||
nom = body.nom.strip()
|
||||
if not nom:
|
||||
raise HTTPException(status_code=400, detail="Le nom du tag ne peut pas être vide.")
|
||||
|
||||
tag = session.query(Tag).filter(Tag.id == tag_id).first()
|
||||
if not tag:
|
||||
raise HTTPException(status_code=404, detail="Tag introuvable.")
|
||||
|
||||
existing = session.query(Tag).filter(Tag.nom == nom, Tag.id != tag_id).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=409, detail=f"Le tag '{nom}' existe déjà.")
|
||||
|
||||
tag.nom = nom
|
||||
session.commit()
|
||||
session.refresh(tag)
|
||||
return {"id": tag.id, "nom": tag.nom}
|
||||
|
||||
@@ -6,11 +6,9 @@ from datetime import datetime
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
|
||||
from fastapi.responses import JSONResponse, Response
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...database import DatabaseService, get_session, storage
|
||||
from ...database.models import Depense, Document, Immeuble, Locataire, Lot, Revenu
|
||||
from ...database.service import DuplicateDocumentError
|
||||
from ...extractor import extract_compte_rendu
|
||||
from ...utils.canonical import canonical_copy
|
||||
@@ -149,24 +147,6 @@ async def save_document_with_pdf(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
async def get_stats(
|
||||
session: Session = Depends(get_session),
|
||||
) -> dict:
|
||||
"""Retourne les statistiques globales de la base de donnees.
|
||||
|
||||
Compteurs pour chaque table principale.
|
||||
"""
|
||||
return {
|
||||
"documents": session.execute(select(func.count(Document.id))).scalar() or 0,
|
||||
"immeubles": session.execute(select(func.count(Immeuble.id))).scalar() or 0,
|
||||
"lots": session.execute(select(func.count(Lot.id))).scalar() or 0,
|
||||
"locataires": session.execute(select(func.count(Locataire.id))).scalar() or 0,
|
||||
"revenus": session.execute(select(func.count(Revenu.id))).scalar() or 0,
|
||||
"depenses": session.execute(select(func.count(Depense.id))).scalar() or 0,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/documents", response_model=list[DocumentSummary])
|
||||
async def list_documents(
|
||||
limit: int = 100,
|
||||
|
||||
@@ -1,15 +1,34 @@
|
||||
"""Tags routes - Tag management and prediction."""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...database import DatabaseService, get_session
|
||||
from ...database.models import Tag
|
||||
from ...services.tag_predictor import TagPredictor
|
||||
from ..schemas import PredictTagsRequest
|
||||
|
||||
router = APIRouter(prefix="/api", tags=["tags"])
|
||||
|
||||
|
||||
class TagBody(BaseModel):
|
||||
"""Corps de requete pour creer ou renommer un tag."""
|
||||
|
||||
nom: str
|
||||
|
||||
|
||||
def _tag_dict(tag: Tag) -> dict:
|
||||
return {"id": tag.id, "nom": tag.nom}
|
||||
|
||||
|
||||
def _nom_valide(nom: str) -> str:
|
||||
nom = nom.strip()
|
||||
if not nom:
|
||||
raise HTTPException(status_code=400, detail="Le nom du tag ne peut pas être vide.")
|
||||
return nom
|
||||
|
||||
|
||||
@router.get("/tags")
|
||||
async def list_tags(
|
||||
session: Session = Depends(get_session),
|
||||
@@ -21,7 +40,47 @@ async def list_tags(
|
||||
db_service = DatabaseService(session)
|
||||
tags = db_service.list_tags()
|
||||
|
||||
return [{"id": tag.id, "nom": tag.nom} for tag in tags]
|
||||
return [_tag_dict(tag) for tag in tags]
|
||||
|
||||
|
||||
@router.post("/tags", status_code=201)
|
||||
async def create_tag(
|
||||
body: TagBody,
|
||||
session: Session = Depends(get_session),
|
||||
) -> dict:
|
||||
"""Cree un nouveau tag (validation unicite)."""
|
||||
nom = _nom_valide(body.nom)
|
||||
|
||||
if session.query(Tag).filter(Tag.nom == nom).first():
|
||||
raise HTTPException(status_code=409, detail=f"Le tag '{nom}' existe déjà.")
|
||||
|
||||
tag = Tag(nom=nom)
|
||||
session.add(tag)
|
||||
session.commit()
|
||||
session.refresh(tag)
|
||||
return _tag_dict(tag)
|
||||
|
||||
|
||||
@router.put("/tags/{tag_id}")
|
||||
async def rename_tag(
|
||||
tag_id: int,
|
||||
body: TagBody,
|
||||
session: Session = Depends(get_session),
|
||||
) -> dict:
|
||||
"""Renomme un tag (validation unicite)."""
|
||||
nom = _nom_valide(body.nom)
|
||||
|
||||
tag = session.query(Tag).filter(Tag.id == tag_id).first()
|
||||
if not tag:
|
||||
raise HTTPException(status_code=404, detail="Tag introuvable.")
|
||||
|
||||
if session.query(Tag).filter(Tag.nom == nom, Tag.id != tag_id).first():
|
||||
raise HTTPException(status_code=409, detail=f"Le tag '{nom}' existe déjà.")
|
||||
|
||||
tag.nom = nom
|
||||
session.commit()
|
||||
session.refresh(tag)
|
||||
return _tag_dict(tag)
|
||||
|
||||
|
||||
@router.post("/predict-tags")
|
||||
|
||||
Reference in New Issue
Block a user