Files
monlet/server/monlet_server/api/outbox.py
2026-05-27 11:01:27 +04:00

60 lines
2.0 KiB
Python

from fastapi import APIRouter, Depends, Query
from sqlalchemy import and_, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
from ..cursors import decode, decode_datetime, encode
from ..db import get_session
from ..models import NotificationOutbox
from ..schemas import NotificationOutboxItem, OutboxPage
from ..timeutil import to_utc
router = APIRouter()
@router.get("/notifiers/outbox", response_model=OutboxPage)
async def list_outbox(
state: str | None = Query(default=None),
cursor: str | None = Query(default=None, max_length=512),
limit: int = Query(default=100, ge=1, le=500),
session: AsyncSession = Depends(get_session),
) -> OutboxPage:
stmt = select(NotificationOutbox).order_by(
NotificationOutbox.created_at.desc(), NotificationOutbox.id.desc()
)
if state is not None:
stmt = stmt.where(NotificationOutbox.state == state)
if cursor is not None:
ts_str, last_id = decode(cursor, 2)
ts = decode_datetime(ts_str)
stmt = stmt.where(
or_(
NotificationOutbox.created_at < ts,
and_(
NotificationOutbox.created_at == ts,
NotificationOutbox.id < last_id,
),
)
)
rows = (await session.execute(stmt.limit(limit + 1))).scalars().all()
next_cursor = None
if len(rows) > limit:
rows = rows[:limit]
next_cursor = encode(to_utc(rows[-1].created_at).isoformat(), rows[-1].id)
return OutboxPage(
items=[
NotificationOutboxItem(
id=str(r.id),
notifier=r.notifier,
state=r.state,
incident_id=str(r.incident_id),
event_type=r.event_type,
attempts=r.attempts,
next_attempt_at=to_utc(r.next_attempt_at) if r.next_attempt_at else None,
last_error=r.last_error,
updated_at=to_utc(r.updated_at),
)
for r in rows
],
next_cursor=next_cursor,
)