Files
notytex/backend/schemas/config.py
Bertrand Benjamin 2b08eb534a Migration v1 (Flask) -> v2 (FastAPI + Vue.js) complétée
 Changements majeurs:
- Suppression complète du code Flask legacy
- Migration backend FastAPI vers racine /backend
- Migration frontend Vue.js vers racine /frontend
- Suppression de notytex-v2/ (code monté à la racine)

 Validations:
- Backend démarre correctement (port 8000)
- API /api/v2/health répond healthy
- 99/99 tests unitaires passent
- Frontend configuré avec proxy Vite

📝 Documentation:
- README.md réécrit pour v2
- Instructions de démarrage mises à jour
- .gitignore adapté pour backend/frontend/

🎯 Architecture finale:
notytex/
├── backend/     # FastAPI + SQLAlchemy + Pydantic
├── frontend/    # Vue 3 + Vite + TailwindCSS
├── docs/        # Documentation
└── school_management.db  # Base de données (inchangée)

Jalon 6 complété: Application v2 prête pour utilisation!
2025-11-25 21:09:47 +01:00

248 lines
6.4 KiB
Python

"""
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