""" Schema Pydantic per TenantSettings – lettura e aggiornamento impostazioni tenant. """ import uuid from datetime import datetime from typing import Literal from pydantic import BaseModel, Field, HttpUrl, field_validator ArchivalMode = Literal["mock", "production"] class TenantSettingsResponse(BaseModel): """ Risposta GET /settings. Le credenziali del conservatore non vengono mai esposte in chiaro: vengono restituite come flag booleani (is_configured). """ id: uuid.UUID tenant_id: uuid.UUID # Archiviazione archival_mode: ArchivalMode conservatore_id: str conservatore_endpoint: str | None conservatore_username_configured: bool # TRUE se la username è già salvata conservatore_password_configured: bool # TRUE se la password è già salvata archival_notes: str | None created_at: datetime updated_at: datetime model_config = {"from_attributes": True} class TenantSettingsUpdate(BaseModel): """ Body PUT /settings. Tutti i campi sono opzionali (PATCH semantics). Le credenziali vengono aggiornate solo se fornite. Un valore esplicitamente None può essere usato per cancellare le credenziali. """ archival_mode: ArchivalMode | None = None conservatore_id: str | None = Field( default=None, min_length=1, max_length=100 ) # URL endpoint del conservatore (obbligatorio in produzione, ignorato in mock) conservatore_endpoint: str | None = None # Credenziali in chiaro: vengono cifrate prima del salvataggio. # Valore stringa vuota ("") = cancella la credenziale. conservatore_username: str | None = None conservatore_password: str | None = None archival_notes: str | None = None @field_validator("archival_mode") @classmethod def validate_archival_mode(cls, v: str | None) -> str | None: if v is not None and v not in ("mock", "production"): raise ValueError("archival_mode deve essere 'mock' o 'production'") return v