from fastapi import FastAPI, Depends, HTTPException from sqlalchemy.orm import Session from sqlalchemy import create_engine, Column, Integer, String, TIMESTAMP, inspect from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from pydantic import BaseModel from typing import List, Optional from fastapi.middleware.cors import CORSMiddleware from datetime import datetime import os # Chargement de la base de données depuis les variables d'environnement DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./test.db") # Connexion conditionnelle selon le moteur utilisé if DATABASE_URL.startswith("sqlite"): engine = create_engine( DATABASE_URL, connect_args={"check_same_thread": False} ) else: engine = create_engine(DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() # Définition de l'application FastAPI app = FastAPI() # Middleware CORS pour autoriser toutes les origines (utile en développement) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Modèle de base de données class TraitementDB(Base): __tablename__ = "traitements" id = Column(Integer, primary_key=True, index=True) uid = Column(String, nullable=False) # Ajout du champ UID date_traitement = Column(TIMESTAMP) type_traitement = Column(String) produit_utilise = Column(String) hectares_traites = Column(Integer, nullable=True) commentaire = Column(String, nullable=True) is_deleted = Column(Integer, default=0) # Fonction utilitaire : créer la table si elle n'existe pas def ensure_table_exists(): inspector = inspect(engine) if "traitements" not in inspector.get_table_names(): print("✅ Table 'traitements' absente, création en cours...") Base.metadata.create_all(bind=engine) else: print("✅ Table 'traitements' déjà présente.") # Dépendance à injecter dans les routes def get_db(): db = SessionLocal() try: yield db finally: db.close() # Schéma de réponse class TraitementResponse(BaseModel): id: int uid: str # Ajout du champ UID date_traitement: datetime type_traitement: str produit_utilise: str hectares_traites: Optional[int] commentaire: Optional[str] is_deleted: int class Config: from_attributes = True # Schéma de création class TraitementCreate(BaseModel): uid: str # Ajout du champ UID date_traitement: str # ISO format attendu côté client type_traitement: str produit_utilise: str hectares_traites: Optional[int] = None commentaire: Optional[str] = None # Routes @app.get("/") def read_root(): return {"message": "Bienvenue sur l'API des traitements"} def convert_db_to_pydantic(db_obj): return TraitementResponse.from_orm(db_obj) @app.get("/traitements", response_model=List[TraitementResponse]) def get_traitements(uid: str, db: Session = Depends(get_db)): db_traitements = db.query(TraitementDB).filter( TraitementDB.is_deleted == 0, TraitementDB.uid == uid ).all() return [convert_db_to_pydantic(t) for t in db_traitements] @app.get("/traitements/all", response_model=List[TraitementResponse]) def get_all_traitements(uid: str, db: Session = Depends(get_db)): db_traitements = db.query(TraitementDB).filter( TraitementDB.uid == uid ).all() return [convert_db_to_pydantic(t) for t in db_traitements] @app.post("/traitements", response_model=TraitementResponse) def create_traitement(traitement: TraitementCreate, db: Session = Depends(get_db)): # Vérification de la table avant l'ajout ensure_table_exists() # Conversion manuelle de la date si nécessaire try: traitement_data = traitement.dict() traitement_data["date_traitement"] = datetime.fromisoformat(traitement.date_traitement) except ValueError: raise HTTPException(status_code=400, detail="Format de date invalide. Utilisez ISO 8601 (ex: 2024-01-01T10:00:00)") db_traitement = TraitementDB(**traitement_data) db.add(db_traitement) db.commit() db.refresh(db_traitement) return convert_db_to_pydantic(db_traitement) @app.patch("/traitements/{treatment_id}/soft-delete", response_model=TraitementResponse) def soft_delete_treatment(treatment_id: int, uid: str, db: Session = Depends(get_db)): traitement = db.query(TraitementDB).filter( TraitementDB.id == treatment_id, TraitementDB.uid == uid ).first() if not traitement: raise HTTPException(status_code=404, detail="Traitement introuvable") traitement.is_deleted = 1 db.commit() return convert_db_to_pydantic(traitement)