mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
vboxes fix
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
"""
|
||||
Service per la gestione delle Label (tag) e la loro assegnazione ai messaggi.
|
||||
"""
|
||||
|
||||
import uuid
|
||||
|
||||
from sqlalchemy import delete, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.exceptions import ConflictError, NotFoundError
|
||||
from app.models.label import Label, MessageLabel
|
||||
from app.models.message import Message
|
||||
from app.schemas.label import LabelCreate, LabelUpdate
|
||||
|
||||
|
||||
class LabelService:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
|
||||
# ─── CRUD Label ───────────────────────────────────────────────────────────
|
||||
|
||||
async def list_labels(self, tenant_id: uuid.UUID) -> list[Label]:
|
||||
result = await self.db.execute(
|
||||
select(Label)
|
||||
.where(Label.tenant_id == tenant_id)
|
||||
.order_by(Label.name)
|
||||
)
|
||||
return list(result.scalars().all())
|
||||
|
||||
async def get_label(self, tenant_id: uuid.UUID, label_id: uuid.UUID) -> Label:
|
||||
result = await self.db.execute(
|
||||
select(Label).where(
|
||||
Label.id == label_id,
|
||||
Label.tenant_id == tenant_id,
|
||||
)
|
||||
)
|
||||
label = result.scalar_one_or_none()
|
||||
if not label:
|
||||
raise NotFoundError(f"Tag {label_id} non trovato")
|
||||
return label
|
||||
|
||||
async def create_label(self, tenant_id: uuid.UUID, data: LabelCreate) -> Label:
|
||||
# Verifica unicità
|
||||
existing = await self.db.execute(
|
||||
select(Label).where(
|
||||
Label.tenant_id == tenant_id,
|
||||
Label.name == data.name,
|
||||
)
|
||||
)
|
||||
if existing.scalar_one_or_none():
|
||||
raise ConflictError(f"Tag '{data.name}' già esistente")
|
||||
|
||||
label = Label(
|
||||
tenant_id=tenant_id,
|
||||
name=data.name,
|
||||
color=data.color,
|
||||
)
|
||||
self.db.add(label)
|
||||
await self.db.commit()
|
||||
await self.db.refresh(label)
|
||||
return label
|
||||
|
||||
async def update_label(
|
||||
self, tenant_id: uuid.UUID, label_id: uuid.UUID, data: LabelUpdate
|
||||
) -> Label:
|
||||
label = await self.get_label(tenant_id, label_id)
|
||||
|
||||
if data.name is not None:
|
||||
# Verifica unicità del nuovo nome
|
||||
existing = await self.db.execute(
|
||||
select(Label).where(
|
||||
Label.tenant_id == tenant_id,
|
||||
Label.name == data.name,
|
||||
Label.id != label_id,
|
||||
)
|
||||
)
|
||||
if existing.scalar_one_or_none():
|
||||
raise ConflictError(f"Tag '{data.name}' già esistente")
|
||||
label.name = data.name
|
||||
|
||||
if data.color is not None:
|
||||
label.color = data.color
|
||||
|
||||
await self.db.commit()
|
||||
await self.db.refresh(label)
|
||||
return label
|
||||
|
||||
async def delete_label(self, tenant_id: uuid.UUID, label_id: uuid.UUID) -> None:
|
||||
label = await self.get_label(tenant_id, label_id)
|
||||
await self.db.delete(label)
|
||||
await self.db.commit()
|
||||
|
||||
# ─── Assegnazione tag a singolo messaggio ─────────────────────────────────
|
||||
|
||||
async def get_message_labels(
|
||||
self, message_id: uuid.UUID, tenant_id: uuid.UUID
|
||||
) -> list[Label]:
|
||||
result = await self.db.execute(
|
||||
select(Label)
|
||||
.join(MessageLabel, Label.id == MessageLabel.label_id)
|
||||
.where(
|
||||
MessageLabel.message_id == message_id,
|
||||
Label.tenant_id == tenant_id,
|
||||
)
|
||||
.order_by(Label.name)
|
||||
)
|
||||
return list(result.scalars().all())
|
||||
|
||||
async def set_message_labels(
|
||||
self,
|
||||
message_id: uuid.UUID,
|
||||
tenant_id: uuid.UUID,
|
||||
label_ids: list[uuid.UUID],
|
||||
) -> list[Label]:
|
||||
"""Sostituisce tutti i tag di un messaggio con quelli indicati."""
|
||||
# Verifica che i label appartengano al tenant
|
||||
valid_ids: set[uuid.UUID] = set()
|
||||
if label_ids:
|
||||
result = await self.db.execute(
|
||||
select(Label).where(
|
||||
Label.id.in_(label_ids),
|
||||
Label.tenant_id == tenant_id,
|
||||
)
|
||||
)
|
||||
valid_ids = {lbl.id for lbl in result.scalars().all()}
|
||||
|
||||
# Rimuovi tutti i tag esistenti dal messaggio
|
||||
await self.db.execute(
|
||||
delete(MessageLabel).where(MessageLabel.message_id == message_id)
|
||||
)
|
||||
|
||||
# Aggiungi i nuovi tag validi
|
||||
for lbl_id in valid_ids:
|
||||
self.db.add(MessageLabel(message_id=message_id, label_id=lbl_id))
|
||||
|
||||
await self.db.commit()
|
||||
return await self.get_message_labels(message_id, tenant_id)
|
||||
|
||||
async def add_message_labels(
|
||||
self,
|
||||
message_id: uuid.UUID,
|
||||
tenant_id: uuid.UUID,
|
||||
label_ids: list[uuid.UUID],
|
||||
) -> list[Label]:
|
||||
"""Aggiunge tag a un messaggio senza rimuovere quelli esistenti."""
|
||||
if not label_ids:
|
||||
return await self.get_message_labels(message_id, tenant_id)
|
||||
|
||||
# Verifica appartenenza al tenant
|
||||
result = await self.db.execute(
|
||||
select(Label).where(
|
||||
Label.id.in_(label_ids),
|
||||
Label.tenant_id == tenant_id,
|
||||
)
|
||||
)
|
||||
valid_labels = list(result.scalars().all())
|
||||
|
||||
# Carica tag esistenti per evitare duplicati
|
||||
existing_result = await self.db.execute(
|
||||
select(MessageLabel.label_id).where(
|
||||
MessageLabel.message_id == message_id
|
||||
)
|
||||
)
|
||||
existing_ids = set(existing_result.scalars().all())
|
||||
|
||||
for lbl in valid_labels:
|
||||
if lbl.id not in existing_ids:
|
||||
self.db.add(MessageLabel(message_id=message_id, label_id=lbl.id))
|
||||
|
||||
await self.db.commit()
|
||||
return await self.get_message_labels(message_id, tenant_id)
|
||||
|
||||
async def remove_message_labels(
|
||||
self,
|
||||
message_id: uuid.UUID,
|
||||
tenant_id: uuid.UUID,
|
||||
label_ids: list[uuid.UUID],
|
||||
) -> list[Label]:
|
||||
"""Rimuove specifici tag da un messaggio."""
|
||||
if label_ids:
|
||||
await self.db.execute(
|
||||
delete(MessageLabel).where(
|
||||
MessageLabel.message_id == message_id,
|
||||
MessageLabel.label_id.in_(label_ids),
|
||||
)
|
||||
)
|
||||
await self.db.commit()
|
||||
return await self.get_message_labels(message_id, tenant_id)
|
||||
|
||||
# ─── Azioni bulk ──────────────────────────────────────────────────────────
|
||||
|
||||
async def bulk_add_labels(
|
||||
self,
|
||||
message_ids: list[uuid.UUID],
|
||||
tenant_id: uuid.UUID,
|
||||
label_ids: list[uuid.UUID],
|
||||
) -> int:
|
||||
"""Aggiunge tag a più messaggi in blocco."""
|
||||
if not label_ids or not message_ids:
|
||||
return 0
|
||||
|
||||
# Verifica label del tenant
|
||||
lbl_result = await self.db.execute(
|
||||
select(Label).where(
|
||||
Label.id.in_(label_ids),
|
||||
Label.tenant_id == tenant_id,
|
||||
)
|
||||
)
|
||||
valid_label_ids = [lbl.id for lbl in lbl_result.scalars().all()]
|
||||
|
||||
# Verifica messaggi del tenant
|
||||
msg_result = await self.db.execute(
|
||||
select(Message.id).where(
|
||||
Message.id.in_(message_ids),
|
||||
Message.tenant_id == tenant_id,
|
||||
)
|
||||
)
|
||||
valid_message_ids = list(msg_result.scalars().all())
|
||||
|
||||
if not valid_label_ids or not valid_message_ids:
|
||||
return 0
|
||||
|
||||
# Carica coppie esistenti per evitare duplicati
|
||||
existing_result = await self.db.execute(
|
||||
select(MessageLabel).where(
|
||||
MessageLabel.message_id.in_(valid_message_ids),
|
||||
MessageLabel.label_id.in_(valid_label_ids),
|
||||
)
|
||||
)
|
||||
existing_pairs = {
|
||||
(ml.message_id, ml.label_id) for ml in existing_result.scalars().all()
|
||||
}
|
||||
|
||||
for msg_id in valid_message_ids:
|
||||
for lbl_id in valid_label_ids:
|
||||
if (msg_id, lbl_id) not in existing_pairs:
|
||||
self.db.add(MessageLabel(message_id=msg_id, label_id=lbl_id))
|
||||
|
||||
await self.db.commit()
|
||||
return len(valid_message_ids)
|
||||
|
||||
async def bulk_remove_labels(
|
||||
self,
|
||||
message_ids: list[uuid.UUID],
|
||||
tenant_id: uuid.UUID,
|
||||
label_ids: list[uuid.UUID],
|
||||
) -> int:
|
||||
"""Rimuove tag da più messaggi in blocco."""
|
||||
if not label_ids or not message_ids:
|
||||
return 0
|
||||
|
||||
# Verifica messaggi del tenant
|
||||
msg_result = await self.db.execute(
|
||||
select(Message.id).where(
|
||||
Message.id.in_(message_ids),
|
||||
Message.tenant_id == tenant_id,
|
||||
)
|
||||
)
|
||||
valid_message_ids = list(msg_result.scalars().all())
|
||||
|
||||
if not valid_message_ids:
|
||||
return 0
|
||||
|
||||
await self.db.execute(
|
||||
delete(MessageLabel).where(
|
||||
MessageLabel.message_id.in_(valid_message_ids),
|
||||
MessageLabel.label_id.in_(label_ids),
|
||||
)
|
||||
)
|
||||
await self.db.commit()
|
||||
return len(valid_message_ids)
|
||||
Reference in New Issue
Block a user