This commit is contained in:
2026-03-18 17:30:13 +01:00
parent 58a233236c
commit d80d912fb3
36 changed files with 3502 additions and 4 deletions
+118
View File
@@ -0,0 +1,118 @@
"""
Schemas Pydantic per le caselle PEC (mailboxes).
Le credenziali vengono accettate in chiaro dalla API e cifrate nel service.
"""
import uuid
from datetime import datetime
from typing import Literal
from pydantic import BaseModel, EmailStr, Field, field_validator
# ─── Request schemas ──────────────────────────────────────────────────────────
class MailboxCreateRequest(BaseModel):
"""Dati per creare una nuova casella PEC."""
email_address: EmailStr = Field(..., description="Indirizzo email PEC")
display_name: str | None = Field(None, max_length=255, description="Nome visualizzato")
provider: str | None = Field(None, max_length=100, description="Provider PEC (aruba, namirial...)")
# Credenziali IMAP (in chiaro, cifrate prima della persistenza)
imap_host: str = Field(..., min_length=1, max_length=255, description="Host IMAP")
imap_port: int = Field(993, ge=1, le=65535, description="Porta IMAP")
imap_user: str = Field(..., min_length=1, max_length=255, description="Username IMAP")
imap_pass: str = Field(..., min_length=1, description="Password IMAP")
imap_use_ssl: bool = Field(True, description="Usa SSL/TLS per IMAP")
# Credenziali SMTP (in chiaro, cifrate prima della persistenza)
smtp_host: str = Field(..., min_length=1, max_length=255, description="Host SMTP")
smtp_port: int = Field(465, ge=1, le=65535, description="Porta SMTP")
smtp_user: str = Field(..., min_length=1, max_length=255, description="Username SMTP")
smtp_pass: str = Field(..., min_length=1, description="Password SMTP")
smtp_use_tls: bool = Field(True, description="Usa TLS per SMTP")
@field_validator("imap_port", "smtp_port")
@classmethod
def validate_port(cls, v: int) -> int:
if v not in range(1, 65536):
raise ValueError("Porta non valida")
return v
class MailboxUpdateRequest(BaseModel):
"""Aggiornamento parziale di una casella PEC."""
display_name: str | None = Field(None, max_length=255)
provider: str | None = Field(None, max_length=100)
status: Literal["active", "paused"] | None = None
# Aggiornamento credenziali IMAP (opzionale)
imap_host: str | None = Field(None, min_length=1, max_length=255)
imap_port: int | None = Field(None, ge=1, le=65535)
imap_user: str | None = Field(None, min_length=1, max_length=255)
imap_pass: str | None = None
imap_use_ssl: bool | None = None
# Aggiornamento credenziali SMTP (opzionale)
smtp_host: str | None = Field(None, min_length=1, max_length=255)
smtp_port: int | None = Field(None, ge=1, le=65535)
smtp_user: str | None = Field(None, min_length=1, max_length=255)
smtp_pass: str | None = None
smtp_use_tls: bool | None = None
# ─── Response schemas ─────────────────────────────────────────────────────────
class MailboxResponse(BaseModel):
"""Risposta API casella PEC NON include mai le credenziali in chiaro."""
id: uuid.UUID
tenant_id: uuid.UUID
email_address: str
display_name: str | None
provider: str | None
# Info IMAP senza credenziali
imap_host: str
imap_port: int
imap_use_ssl: bool
# Info SMTP senza credenziali
smtp_host: str
smtp_port: int
smtp_use_tls: bool
# Stato sync
status: str
last_sync_at: datetime | None
last_sync_uid: int | None
sync_error_msg: str | None
sync_error_count: int
created_by: uuid.UUID | None
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
class MailboxListResponse(BaseModel):
items: list[MailboxResponse]
total: int
page: int
page_size: int
class ConnectionTestRequest(BaseModel):
"""Test connessione IMAP/SMTP per una casella esistente o per credenziali nuove."""
protocol: Literal["imap", "smtp"] = Field("imap", description="Protocollo da testare")
class ConnectionTestResult(BaseModel):
success: bool
message: str
latency_ms: float | None = None
capabilities: list[str] | None = None # Solo per IMAP