Fascicoli+Tassonomia+permessi

This commit is contained in:
2026-06-17 21:47:46 +02:00
parent e31676d22e
commit 3fd3c72f06
42 changed files with 4554 additions and 99 deletions
+92
View File
@@ -0,0 +1,92 @@
"""
Schemi Pydantic per Fascicolo (fascicolazione pratiche).
"""
import uuid
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field
# ─── Schemi base ──────────────────────────────────────────────────────────────
class FascicoloCreate(BaseModel):
titolo: str = Field(..., min_length=1, max_length=255)
numero_pratica: Optional[str] = Field(None, max_length=100)
stato: Optional[str] = Field("aperto", pattern=r"^(aperto|chiuso|archiviato)$")
categoria: Optional[str] = Field(None, max_length=100)
responsabile_id: Optional[uuid.UUID] = None
scadenza: Optional[datetime] = None
note: Optional[str] = None
class FascicoloUpdate(BaseModel):
titolo: Optional[str] = Field(None, min_length=1, max_length=255)
numero_pratica: Optional[str] = Field(None, max_length=100)
stato: Optional[str] = Field(None, pattern=r"^(aperto|chiuso|archiviato)$")
categoria: Optional[str] = Field(None, max_length=100)
responsabile_id: Optional[uuid.UUID] = None
scadenza: Optional[datetime] = None
note: Optional[str] = None
class FascicoloResponse(BaseModel):
id: uuid.UUID
tenant_id: uuid.UUID
titolo: str
numero_pratica: Optional[str] = None
stato: str
categoria: Optional[str] = None
responsabile_id: Optional[uuid.UUID] = None
scadenza: Optional[datetime] = None
note: Optional[str] = None
created_by: Optional[uuid.UUID] = None
created_at: datetime
updated_at: datetime
message_count: int = 0
model_config = {"from_attributes": True}
# ─── Messaggi nel fascicolo ───────────────────────────────────────────────────
class FascicoloMessageItem(BaseModel):
"""Riepilogo di un messaggio nel fascicolo."""
id: uuid.UUID
subject: Optional[str] = None
from_address: Optional[str] = None
to_addresses: Optional[list[str]] = None
direction: str
pec_type: str
state: str
mailbox_id: uuid.UUID
received_at: Optional[datetime] = None
sent_at: Optional[datetime] = None
created_at: datetime
added_at: datetime
model_config = {"from_attributes": True}
# ─── Operazioni sui messaggi del fascicolo ────────────────────────────────────
class FascicoloAddMessagesRequest(BaseModel):
message_ids: list[uuid.UUID] = Field(..., min_length=1)
class FascicoloRemoveMessagesRequest(BaseModel):
message_ids: list[uuid.UUID] = Field(..., min_length=1)
# ─── Lista fascicoli di un messaggio ─────────────────────────────────────────
class MessageFascicoloSummary(BaseModel):
"""Fascicolo sintetico per la vista nel dettaglio messaggio."""
id: uuid.UUID
titolo: str
numero_pratica: Optional[str] = None
stato: str
categoria: Optional[str] = None
model_config = {"from_attributes": True}
+32
View File
@@ -1,5 +1,6 @@
"""
Schemi Pydantic per Label (tag) e operazioni correlate.
Esteso con supporto tassonomia gerarchica (Feature N2).
"""
import uuid
@@ -8,14 +9,21 @@ from typing import Optional
from pydantic import BaseModel, Field
# ─── CRUD Label ───────────────────────────────────────────────────────────────
class LabelCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
color: Optional[str] = Field(None, pattern=r'^#[0-9A-Fa-f]{6}$')
# Tassonomia: se valorizzato, questo nodo diventa figlio del parent indicato
parent_id: Optional[uuid.UUID] = None
description: Optional[str] = None
class LabelUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=100)
color: Optional[str] = Field(None, pattern=r'^#[0-9A-Fa-f]{6}$')
parent_id: Optional[uuid.UUID] = None
description: Optional[str] = None
class LabelResponse(BaseModel):
@@ -23,10 +31,34 @@ class LabelResponse(BaseModel):
tenant_id: uuid.UUID
name: str
color: Optional[str] = None
parent_id: Optional[uuid.UUID] = None
description: Optional[str] = None
model_config = {"from_attributes": True}
class LabelTreeResponse(BaseModel):
"""
Label con figli annidati per la vista ad albero della tassonomia.
Struttura restituita da GET /labels/tree:
[ Ambito1 { children: [ Processo1 { children: [ Classificazione1, ... ] } ] } ]
"""
id: uuid.UUID
tenant_id: uuid.UUID
name: str
color: Optional[str] = None
parent_id: Optional[uuid.UUID] = None
description: Optional[str] = None
children: list["LabelTreeResponse"] = []
model_config = {"from_attributes": True}
# Necessario per il tipo ricorsivo
LabelTreeResponse.model_rebuild()
# ─── Richieste per assegnazione tag a messaggi ────────────────────────────────
class MessageLabelSetRequest(BaseModel):
+8
View File
@@ -76,6 +76,9 @@ class MessageResponse(BaseModel):
pending_conservation_at: Optional[datetime] = None
is_conserved: bool = False
conserved_at: Optional[datetime] = None
# Rischio e Riservatezza (Feature N3)
risk_level: Optional[str] = None
confidentiality: Optional[str] = None
raw_eml_path: Optional[str] = None
created_at: datetime
updated_at: datetime
@@ -116,6 +119,9 @@ class MessageUpdateRequest(BaseModel):
is_trashed: Optional[bool] = None
is_pending_conservation: Optional[bool] = None
is_conserved: Optional[bool] = None
# Rischio e Riservatezza (Feature N3) — None = non modificare; stringa vuota = reset a NULL
risk_level: Optional[str] = None
confidentiality: Optional[str] = None
class MessageBulkUpdateRequest(BaseModel):
@@ -126,6 +132,8 @@ class MessageBulkUpdateRequest(BaseModel):
is_trashed: Optional[bool] = None
is_pending_conservation: Optional[bool] = None
is_conserved: Optional[bool] = None
risk_level: Optional[str] = None
confidentiality: Optional[str] = None
class MessageBulkUpdateResponse(BaseModel):
+42
View File
@@ -0,0 +1,42 @@
"""
Schema Pydantic per i preset di permessi (sottoruoli nominati).
"""
import uuid
from datetime import datetime
from pydantic import BaseModel, Field
class PermissionPresetCreate(BaseModel):
name: str = Field(..., min_length=1, max_length=100, description="Nome del preset")
description: str | None = Field(None, description="Descrizione opzionale")
can_read: bool = Field(True, description="Permesso lettura messaggi")
can_send: bool = Field(False, description="Permesso invio PEC")
can_manage: bool = Field(False, description="Permesso gestione casella")
can_conserve: bool = Field(False, description="Permesso conservazione documenti")
class PermissionPresetUpdate(BaseModel):
name: str | None = Field(None, min_length=1, max_length=100)
description: str | None = None
can_read: bool | None = None
can_send: bool | None = None
can_manage: bool | None = None
can_conserve: bool | None = None
class PermissionPresetResponse(BaseModel):
id: uuid.UUID
tenant_id: uuid.UUID
name: str
description: str | None
can_read: bool
can_send: bool
can_manage: bool
can_conserve: bool
created_by: uuid.UUID | None
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
+20 -2
View File
@@ -10,7 +10,16 @@ from pydantic import BaseModel, field_validator
# Valori validi per field nelle condizioni
CONDITION_FIELDS = Literal[
"from_address", "to_address", "subject", "mailbox_id", "pec_type"
"from_address",
"to_address",
"subject",
"mailbox_id",
"pec_type",
# Tassonomia (N2): verifica se il messaggio ha gia' una specifica etichetta/nodo
"has_label",
# Rischio e Riservatezza (N3): verifica il livello gia' impostato
"risk_level",
"confidentiality",
]
# Operatori supportati
CONDITION_OPERATORS = Literal[
@@ -18,7 +27,16 @@ CONDITION_OPERATORS = Literal[
]
# Tipi di azione
ACTION_TYPES = Literal[
"apply_label", "assign_vbox", "mark_read", "mark_starred", "notify_webhook"
"apply_label",
"assign_vbox",
"mark_read",
"mark_starred",
"notify_webhook",
# Tassonomia (N2): applica un nodo tassonomico (Ambito/Processo/Classificazione)
"apply_taxonomy",
# Rischio e Riservatezza (N3): imposta il livello di rischio o riservatezza
"set_risk_level",
"set_confidentiality",
]