mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
238 lines
8.3 KiB
Python
238 lines
8.3 KiB
Python
"""
|
||
Router tag (Label).
|
||
|
||
Endpoint:
|
||
- GET /labels – elenca i tag del tenant
|
||
- POST /labels – crea un nuovo tag (admin)
|
||
- PATCH /labels/{id} – modifica un tag (admin)
|
||
- DELETE /labels/{id} – elimina un tag (admin)
|
||
|
||
- GET /messages/{id}/labels – tag di un messaggio
|
||
- PUT /messages/{id}/labels – imposta i tag di un messaggio (sostituisce)
|
||
- POST /messages/{id}/labels/add – aggiunge tag a un messaggio
|
||
- POST /messages/{id}/labels/remove – rimuove tag da un messaggio
|
||
|
||
- POST /messages/bulk-labels – aggiunge/rimuove tag in blocco
|
||
|
||
Permessi:
|
||
- GET /labels: tutti gli utenti autenticati
|
||
- POST/PATCH/DELETE: solo admin
|
||
- Operazioni su messaggi: utenti con accesso alla casella del messaggio
|
||
"""
|
||
|
||
import uuid
|
||
|
||
from fastapi import APIRouter, status
|
||
from sqlalchemy import select
|
||
|
||
from app.core.exceptions import ForbiddenError, NotFoundError
|
||
from app.dependencies import AdminUser, CurrentUser, DB
|
||
from app.models.message import Message
|
||
from app.schemas.label import (
|
||
LabelCreate,
|
||
LabelResponse,
|
||
LabelUpdate,
|
||
MessageBulkLabelRequest,
|
||
MessageBulkLabelResponse,
|
||
MessageLabelAddRequest,
|
||
MessageLabelRemoveRequest,
|
||
MessageLabelSetRequest,
|
||
)
|
||
from app.services.label_service import LabelService
|
||
|
||
router = APIRouter(tags=["Labels"])
|
||
|
||
|
||
# ─── Helpers ──────────────────────────────────────────────────────────────────
|
||
|
||
async def _check_message_access(
|
||
message_id: uuid.UUID,
|
||
current_user,
|
||
db,
|
||
) -> Message:
|
||
"""Verifica che il messaggio esista e l'utente vi abbia accesso."""
|
||
result = await db.execute(
|
||
select(Message).where(
|
||
Message.id == message_id,
|
||
Message.tenant_id == current_user.tenant_id,
|
||
)
|
||
)
|
||
message = result.scalar_one_or_none()
|
||
if not message:
|
||
raise NotFoundError(f"Messaggio {message_id} non trovato")
|
||
|
||
if not current_user.is_admin:
|
||
from app.services.permission_service import PermissionService
|
||
perm_svc = PermissionService(db)
|
||
if not await perm_svc.check_can_read(current_user, message.mailbox_id):
|
||
raise ForbiddenError("Accesso al messaggio non autorizzato")
|
||
|
||
return message
|
||
|
||
|
||
# ─── CRUD Label ───────────────────────────────────────────────────────────────
|
||
|
||
@router.get("/labels", response_model=list[LabelResponse])
|
||
async def list_labels(
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
) -> list[LabelResponse]:
|
||
"""Elenca tutti i tag del tenant corrente."""
|
||
svc = LabelService(db)
|
||
labels = await svc.list_labels(current_user.tenant_id)
|
||
return [LabelResponse.model_validate(l) for l in labels]
|
||
|
||
|
||
@router.post("/labels", response_model=LabelResponse, status_code=status.HTTP_201_CREATED)
|
||
async def create_label(
|
||
data: LabelCreate,
|
||
current_user: AdminUser,
|
||
db: DB,
|
||
) -> LabelResponse:
|
||
"""Crea un nuovo tag (solo admin)."""
|
||
svc = LabelService(db)
|
||
label = await svc.create_label(current_user.tenant_id, data)
|
||
return LabelResponse.model_validate(label)
|
||
|
||
|
||
@router.patch("/labels/{label_id}", response_model=LabelResponse)
|
||
async def update_label(
|
||
label_id: uuid.UUID,
|
||
data: LabelUpdate,
|
||
current_user: AdminUser,
|
||
db: DB,
|
||
) -> LabelResponse:
|
||
"""Modifica un tag esistente (solo admin)."""
|
||
svc = LabelService(db)
|
||
label = await svc.update_label(current_user.tenant_id, label_id, data)
|
||
return LabelResponse.model_validate(label)
|
||
|
||
|
||
@router.delete("/labels/{label_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||
async def delete_label(
|
||
label_id: uuid.UUID,
|
||
current_user: AdminUser,
|
||
db: DB,
|
||
) -> None:
|
||
"""Elimina un tag (solo admin). Viene rimosso automaticamente da tutti i messaggi."""
|
||
svc = LabelService(db)
|
||
await svc.delete_label(current_user.tenant_id, label_id)
|
||
|
||
|
||
# ─── Tag su singolo messaggio ─────────────────────────────────────────────────
|
||
|
||
@router.get("/messages/{message_id}/labels", response_model=list[LabelResponse])
|
||
async def get_message_labels(
|
||
message_id: uuid.UUID,
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
) -> list[LabelResponse]:
|
||
"""Elenca i tag assegnati a un messaggio."""
|
||
await _check_message_access(message_id, current_user, db)
|
||
svc = LabelService(db)
|
||
labels = await svc.get_message_labels(message_id, current_user.tenant_id)
|
||
return [LabelResponse.model_validate(l) for l in labels]
|
||
|
||
|
||
@router.put("/messages/{message_id}/labels", response_model=list[LabelResponse])
|
||
async def set_message_labels(
|
||
message_id: uuid.UUID,
|
||
data: MessageLabelSetRequest,
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
) -> list[LabelResponse]:
|
||
"""
|
||
Sostituisce tutti i tag di un messaggio.
|
||
Passare una lista vuota per rimuovere tutti i tag.
|
||
"""
|
||
await _check_message_access(message_id, current_user, db)
|
||
svc = LabelService(db)
|
||
labels = await svc.set_message_labels(
|
||
message_id, current_user.tenant_id, data.label_ids
|
||
)
|
||
return [LabelResponse.model_validate(l) for l in labels]
|
||
|
||
|
||
@router.post("/messages/{message_id}/labels/add", response_model=list[LabelResponse])
|
||
async def add_message_labels(
|
||
message_id: uuid.UUID,
|
||
data: MessageLabelAddRequest,
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
) -> list[LabelResponse]:
|
||
"""Aggiunge tag a un messaggio senza rimuovere quelli esistenti."""
|
||
await _check_message_access(message_id, current_user, db)
|
||
svc = LabelService(db)
|
||
labels = await svc.add_message_labels(
|
||
message_id, current_user.tenant_id, data.label_ids
|
||
)
|
||
return [LabelResponse.model_validate(l) for l in labels]
|
||
|
||
|
||
@router.post("/messages/{message_id}/labels/remove", response_model=list[LabelResponse])
|
||
async def remove_message_labels(
|
||
message_id: uuid.UUID,
|
||
data: MessageLabelRemoveRequest,
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
) -> list[LabelResponse]:
|
||
"""Rimuove specifici tag da un messaggio."""
|
||
await _check_message_access(message_id, current_user, db)
|
||
svc = LabelService(db)
|
||
labels = await svc.remove_message_labels(
|
||
message_id, current_user.tenant_id, data.label_ids
|
||
)
|
||
return [LabelResponse.model_validate(l) for l in labels]
|
||
|
||
|
||
# ─── Bulk labels ──────────────────────────────────────────────────────────────
|
||
|
||
@router.post("/messages/bulk-labels", response_model=MessageBulkLabelResponse)
|
||
async def bulk_labels(
|
||
data: MessageBulkLabelRequest,
|
||
current_user: CurrentUser,
|
||
db: DB,
|
||
) -> MessageBulkLabelResponse:
|
||
"""
|
||
Aggiunge o rimuove tag da più messaggi in blocco.
|
||
|
||
- action="add": aggiunge i tag ai messaggi indicati
|
||
- action="remove": rimuove i tag dai messaggi indicati
|
||
|
||
I messaggi non accessibili all'utente vengono silenziosamente ignorati.
|
||
"""
|
||
if not data.message_ids or not data.label_ids:
|
||
return MessageBulkLabelResponse(updated=0)
|
||
|
||
# Per utenti non-admin filtra per caselle accessibili
|
||
message_ids = [str(mid) for mid in data.message_ids]
|
||
if not current_user.is_admin:
|
||
from app.services.permission_service import PermissionService
|
||
perm_svc = PermissionService(db)
|
||
visible = await perm_svc.get_visible_mailboxes(current_user)
|
||
visible_set = set(visible) if visible else set()
|
||
|
||
# Filtra i messaggi per caselle visibili
|
||
result = await db.execute(
|
||
select(Message.id).where(
|
||
Message.id.in_(data.message_ids),
|
||
Message.tenant_id == current_user.tenant_id,
|
||
Message.mailbox_id.in_(visible_set),
|
||
)
|
||
)
|
||
filtered_ids = list(result.scalars().all())
|
||
else:
|
||
filtered_ids = data.message_ids
|
||
|
||
svc = LabelService(db)
|
||
if data.action == "add":
|
||
updated = await svc.bulk_add_labels(
|
||
filtered_ids, current_user.tenant_id, data.label_ids
|
||
)
|
||
else:
|
||
updated = await svc.bulk_remove_labels(
|
||
filtered_ids, current_user.tenant_id, data.label_ids
|
||
)
|
||
|
||
return MessageBulkLabelResponse(updated=updated)
|