"""Validation Pydantic du document carte envoye au serveur. Le backend ne cherche pas a comprendre finement une carte : il valide sa structure, ses limites de taille, puis la stocke telle quelle. `extra="allow"` garantit qu'une version future du format frontend reste acceptee. """ from __future__ import annotations from typing import Any from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from app.config import get_settings MAX_SUPPORTED_MAP_VERSION = 100 class MapNodeIn(BaseModel): model_config = ConfigDict(extra="allow") id: str = Field(min_length=1, max_length=128) text: str = Field(default="", max_length=5000) class MapEdgeIn(BaseModel): model_config = ConfigDict(extra="allow") id: str = Field(min_length=1, max_length=256) source: str = Field(min_length=1, max_length=128) target: str = Field(min_length=1, max_length=128) class MapDocumentIn(BaseModel): """Document carte complet, tel que produit par le frontend.""" model_config = ConfigDict(extra="allow") version: int = Field(ge=1, le=MAX_SUPPORTED_MAP_VERSION) id: str = Field(min_length=1, max_length=128) name: str = Field(default="", max_length=255) nodes: list[MapNodeIn] = Field(default_factory=list) edges: list[MapEdgeIn] = Field(default_factory=list) viewport: dict[str, Any] = Field(default_factory=dict) settings: dict[str, Any] = Field(default_factory=dict) @field_validator("nodes") @classmethod def _check_node_count(cls, value: list[MapNodeIn]) -> list[MapNodeIn]: max_nodes = get_settings().max_nodes if len(value) > max_nodes: raise ValueError( f"La carte depasse la limite de {max_nodes} noeuds ({len(value)} noeuds fournis)." ) return value @model_validator(mode="after") def _check_edge_count(self) -> MapDocumentIn: max_edges = get_settings().max_nodes * 4 if len(self.edges) > max_edges: raise ValueError(f"La carte depasse la limite de {max_edges} liens.") return self