Files
2026-04-04 13:53:57 -04:00

63 lines
1.8 KiB
Python

"""Alert history and acknowledgement endpoints."""
import time
from fastapi import APIRouter, Depends, Query
from ..auth import require_session, require_session_and_csrf
from ..storage import get_redis
router = APIRouter(prefix="/api/alerts")
@router.get("")
async def list_alerts(
ups: str | None = Query(None),
severity: str | None = Query(None),
days: int = Query(30, ge=1, le=90),
user=Depends(require_session),
):
r = get_redis()
raw = r.lrange("ups:alerts:history:all", 0, -1)
cutoff = int(time.time()) - days * 86400
out = []
for item in raw:
parts = item.split("|", 5)
if len(parts) < 5:
continue
try:
ts = int(parts[0])
except ValueError:
continue
if ts < cutoff:
continue
row = {
"ts": ts,
"severity": parts[1],
"ups": parts[2],
"code": parts[3],
"message": parts[4],
"id": parts[5] if len(parts) > 5 else "",
}
if ups and row["ups"] != ups:
continue
if severity and row["severity"] != severity.upper():
continue
ack = r.get(f"ups:alerts:ack:{row['id']}")
row["acked_ts"] = int(ack) if ack else None
out.append(row)
return out
@router.get("/active")
async def list_active(user=Depends(require_session)):
"""Active alerts = history entries not yet acknowledged, most recent first."""
all_alerts = await list_alerts(days=7, user=user)
return [a for a in all_alerts if not a.get("acked_ts")]
@router.post("/{alert_id}/ack")
async def ack_alert(alert_id: str, user=Depends(require_session_and_csrf)):
r = get_redis()
r.set(f"ups:alerts:ack:{alert_id}", int(time.time()), ex=30 * 86400)
return {"message": "acknowledged"}