""" Schemas Pydantic pour la configuration. """ from datetime import datetime from typing import Optional, List from pydantic import Field from schemas.common import BaseSchema class CompetenceRead(BaseSchema): """Schema pour la lecture d'une compétence.""" id: int name: str color: str icon: str order_index: int class CompetenceList(BaseSchema): """Liste des compétences.""" competences: List[CompetenceRead] class DomainRead(BaseSchema): """Schema pour la lecture d'un domaine.""" id: int name: str color: str description: Optional[str] = None class DomainList(BaseSchema): """Liste des domaines.""" domains: List[DomainRead] class ScaleValueRead(BaseSchema): """Schema pour une valeur d'échelle de compétence.""" value: str label: str color: str included_in_total: bool class ScaleRead(BaseSchema): """Échelle de compétences complète.""" values: List[ScaleValueRead] class AppConfigRead(BaseSchema): """Configuration de l'application.""" school_year: str school_name: str default_grading_system: str class FullConfigRead(BaseSchema): """Configuration complète.""" app_config: AppConfigRead competences: List[CompetenceRead] domains: List[DomainRead] scale: ScaleRead # Schemas de création/mise à jour class CompetenceCreate(BaseSchema): """Schema pour la création d'une compétence.""" name: str = Field(..., min_length=1, max_length=100) color: str = Field(..., pattern=r'^#[0-9a-fA-F]{6}$') icon: str = Field(default="star") order_index: Optional[int] = None class CompetenceUpdate(BaseSchema): """Schema pour la mise à jour d'une compétence.""" name: Optional[str] = Field(None, min_length=1, max_length=100) color: Optional[str] = Field(None, pattern=r'^#[0-9a-fA-F]{6}$') icon: Optional[str] = None order_index: Optional[int] = None class DomainCreate(BaseSchema): """Schema pour la création d'un domaine.""" name: str = Field(..., min_length=1, max_length=100) color: str = Field(..., pattern=r'^#[0-9a-fA-F]{6}$') description: Optional[str] = None class DomainUpdate(BaseSchema): """Schema pour la mise à jour d'un domaine.""" name: Optional[str] = Field(None, min_length=1, max_length=100) color: Optional[str] = Field(None, pattern=r'^#[0-9a-fA-F]{6}$') description: Optional[str] = None class ScaleValueCreate(BaseSchema): """Schema pour la création d'une valeur d'échelle.""" value: str = Field(..., min_length=1, max_length=10) label: str = Field(..., min_length=1, max_length=100) color: str = Field(..., pattern=r'^#[0-9a-fA-F]{6}$') included_in_total: bool = True class ScaleValueUpdate(BaseSchema): """Schema pour la mise à jour d'une valeur d'échelle.""" value: Optional[str] = Field(None, min_length=1, max_length=10) label: Optional[str] = Field(None, min_length=1, max_length=100) color: Optional[str] = Field(None, pattern=r'^#[0-9a-fA-F]{6}$') included_in_total: Optional[bool] = None class AppConfigUpdate(BaseSchema): """Schema pour la mise à jour de la configuration générale.""" school_year: Optional[str] = None school_name: Optional[str] = None default_grading_system: Optional[str] = Field(None, pattern=r'^(notes|score)$') class ConfigResponse(BaseSchema): """Réponse pour les opérations CRUD de configuration.""" success: bool message: str # SMTP Email Configuration schemas class SMTPConfigRead(BaseSchema): """Configuration SMTP pour l'envoi d'emails.""" host: str = "" port: int = 587 username: str = "" use_tls: bool = True from_name: str = "Notytex" from_address: str = "" is_configured: bool = False # Indique si la config est complète class SMTPConfigUpdate(BaseSchema): """Schema pour la mise à jour de la configuration SMTP.""" host: Optional[str] = None port: Optional[int] = Field(None, ge=1, le=65535) username: Optional[str] = None password: Optional[str] = None # Envoyé mais non retourné use_tls: Optional[bool] = None from_name: Optional[str] = None from_address: Optional[str] = Field(None, pattern=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$') class SMTPTestRequest(BaseSchema): """Requête pour tester la configuration SMTP.""" test_email: str = Field(..., pattern=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$') class SMTPTestResponse(BaseSchema): """Réponse du test de configuration SMTP.""" success: bool message: str # Notes Gradient Configuration schemas class NotesGradientRead(BaseSchema): """Configuration du dégradé de couleurs pour les notes.""" min_color: str = "#dc2626" # Rouge pour note 0 max_color: str = "#059669" # Vert pour note max enabled: bool = False class NotesGradientUpdate(BaseSchema): """Schema pour la mise à jour du dégradé des notes.""" min_color: Optional[str] = Field(None, pattern=r'^#[0-9a-fA-F]{6}$') max_color: Optional[str] = Field(None, pattern=r'^#[0-9a-fA-F]{6}$') enabled: Optional[bool] = None # Scale batch update class ScaleValueBatchItem(BaseSchema): """Un item pour la mise à jour batch de l'échelle.""" value: str label: str color: str = Field(..., pattern=r'^#[0-9a-fA-F]{6}$') included_in_total: bool = True class ScaleBatchUpdate(BaseSchema): """Schema pour la mise à jour batch de l'échelle.""" values: List[ScaleValueBatchItem] # Database Configuration schemas class DatabaseConfigRead(BaseSchema): """Configuration de la base de données.""" path: str # Chemin configuré (peut être relatif) resolved_path: str # Chemin absolu résolu exists: bool # Si le fichier existe size_bytes: Optional[int] = None # Taille du fichier si existe size_human: Optional[str] = None # Taille lisible (ex: "2.5 MB") class DatabaseConfigUpdate(BaseSchema): """Schema pour la mise à jour du chemin de la base de données. Note: Cette modification nécessite un redémarrage de l'application. Le nouveau chemin sera utilisé au prochain démarrage. """ path: str = Field(..., min_length=1, description="Chemin vers le fichier SQLite") class DatabaseConfigResponse(BaseSchema): """Réponse après mise à jour de la configuration de base de données.""" success: bool message: str requires_restart: bool = True new_path: Optional[str] = None