Files
2026-03-27 20:59:06 +01:00

153 lines
4.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Router scadenzario e tracking deadlines (Feature 4).
Endpoint:
GET /deadlines messaggi con scadenze imminenti
POST /messages/{id}/deadline imposta/modifica/rimuove scadenza
"""
import uuid
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Query
from pydantic import BaseModel
from sqlalchemy import and_, select
from app.dependencies import CurrentUser, DB
from app.models.message import Message
from app.schemas.message import MessageResponse
from app.core.exceptions import NotFoundError
router = APIRouter(tags=["Deadlines"])
class DeadlineSetRequest(BaseModel):
deadline_at: datetime | None = None
"""Imposta a null per rimuovere la scadenza."""
deadline_note: str | None = None
class DeadlineMessageResponse(BaseModel):
model_config = {"from_attributes": True}
id: uuid.UUID
subject: str | None
from_address: str | None
to_addresses: list[str] | None = None
direction: str
pec_type: str
state: str
mailbox_id: uuid.UUID
deadline_at: datetime | None = None
deadline_note: str | None = None
is_overdue: bool = False
received_at: datetime | None = None
sent_at: datetime | None = None
created_at: datetime
@router.get("/deadlines", response_model=list[DeadlineMessageResponse])
async def list_deadlines(
current_user: CurrentUser,
db: DB,
days_ahead: int = Query(30, ge=1, le=365, description="Giorni da considerare in avanti"),
include_overdue: bool = Query(True, description="Includi scadenze gia' passate"),
) -> list[DeadlineMessageResponse]:
"""
Restituisce i messaggi con scadenze nel range specificato.
Ordinati per: scaduti prima, poi per deadline_at ASC.
"""
now = datetime.now(timezone.utc)
future_limit = now + timedelta(days=days_ahead)
conditions = [
Message.tenant_id == current_user.tenant_id,
Message.deadline_at.is_not(None),
Message.is_trashed == False, # noqa: E712
]
if include_overdue:
# Include scaduti e futuri fino al limite
conditions.append(Message.deadline_at <= future_limit)
else:
# Solo scadenze future
conditions.append(and_(Message.deadline_at > now, Message.deadline_at <= future_limit))
result = await db.execute(
select(Message)
.where(and_(*conditions))
.order_by(Message.deadline_at)
.limit(200)
)
messages = list(result.scalars().all())
items = []
for msg in messages:
is_overdue = msg.deadline_at < now if msg.deadline_at else False
items.append(DeadlineMessageResponse(
id=msg.id,
subject=msg.subject,
from_address=msg.from_address,
to_addresses=msg.to_addresses,
direction=msg.direction,
pec_type=msg.pec_type,
state=msg.state,
mailbox_id=msg.mailbox_id,
deadline_at=msg.deadline_at,
deadline_note=msg.deadline_note,
is_overdue=is_overdue,
received_at=msg.received_at,
sent_at=msg.sent_at,
created_at=msg.created_at,
))
return items
@router.post("/messages/{message_id}/deadline", response_model=DeadlineMessageResponse)
async def set_deadline(
message_id: uuid.UUID,
data: DeadlineSetRequest,
current_user: CurrentUser,
db: DB,
) -> DeadlineMessageResponse:
"""
Imposta, modifica o rimuove la scadenza di un messaggio.
Passa deadline_at=null per rimuovere la scadenza.
"""
result = await db.execute(
select(Message).where(
Message.id == message_id,
Message.tenant_id == current_user.tenant_id,
)
)
msg = result.scalar_one_or_none()
if not msg:
raise NotFoundError(f"Messaggio {message_id} non trovato")
msg.deadline_at = data.deadline_at
msg.deadline_note = data.deadline_note
await db.commit()
await db.refresh(msg)
now = datetime.now(timezone.utc)
is_overdue = msg.deadline_at < now if msg.deadline_at else False
return DeadlineMessageResponse(
id=msg.id,
subject=msg.subject,
from_address=msg.from_address,
to_addresses=msg.to_addresses,
direction=msg.direction,
pec_type=msg.pec_type,
state=msg.state,
mailbox_id=msg.mailbox_id,
deadline_at=msg.deadline_at,
deadline_note=msg.deadline_note,
is_overdue=is_overdue,
received_at=msg.received_at,
sent_at=msg.sent_at,
created_at=msg.created_at,
)