Files
planet/backend/app/api/v1/alerts.py
rayd1o de32552159 feat: add data sources config system and Earth API integration
- Add data_sources.yaml for configurable data source URLs
- Add data_sources.py to load config with database override support
- Add arcgis_landing_points and arcgis_cable_landing_relation collectors
- Change visualization API to query arcgis_landing_points
- Add /api/v1/datasources/configs/all endpoint
- Update Earth to fetch from API instead of static files
- Fix scheduler collector ID mappings
2026-03-13 10:54:02 +08:00

126 lines
3.6 KiB
Python

from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends
from sqlalchemy import select, func, case
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.session import get_db
from app.models.user import User
from app.core.security import get_current_user
from app.models.alert import Alert, AlertSeverity, AlertStatus
router = APIRouter()
@router.get("")
async def list_alerts(
severity: str = None,
status: str = None,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
query = select(Alert)
if severity:
query = query.where(Alert.severity == AlertSeverity(severity))
if status:
query = query.where(Alert.status == AlertStatus(status))
query = query.order_by(
case(
(Alert.severity == AlertSeverity.CRITICAL, 1),
(Alert.severity == AlertSeverity.WARNING, 2),
(Alert.severity == AlertSeverity.INFO, 3),
),
Alert.created_at.desc(),
)
result = await db.execute(query)
alerts = result.scalars().all()
total_query = select(func.count(Alert.id))
if severity:
total_query = total_query.where(Alert.severity == AlertSeverity(severity))
if status:
total_query = total_query.where(Alert.status == AlertStatus(status))
total_result = await db.execute(total_query)
total = total_result.scalar()
return {
"total": total,
"data": [alert.to_dict() for alert in alerts],
}
@router.post("/{alert_id}/acknowledge")
async def acknowledge_alert(
alert_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(Alert).where(Alert.id == alert_id))
alert = result.scalar_one_or_none()
if not alert:
return {"error": "Alert not found"}
alert.status = AlertStatus.ACKNOWLEDGED
alert.acknowledged_by = current_user.id
alert.acknowledged_at = datetime.utcnow()
await db.commit()
return {"message": "Alert acknowledged", "alert": alert.to_dict()}
@router.post("/{alert_id}/resolve")
async def resolve_alert(
alert_id: int,
resolution: str,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
result = await db.execute(select(Alert).where(Alert.id == alert_id))
alert = result.scalar_one_or_none()
if not alert:
return {"error": "Alert not found"}
alert.status = AlertStatus.RESOLVED
alert.resolved_by = current_user.id
alert.resolved_at = datetime.utcnow()
alert.resolution_notes = resolution
await db.commit()
return {"message": "Alert resolved", "alert": alert.to_dict()}
@router.get("/stats")
async def get_alert_stats(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
critical_query = select(func.count(Alert.id)).where(
Alert.severity == AlertSeverity.CRITICAL,
Alert.status == AlertStatus.ACTIVE,
)
warning_query = select(func.count(Alert.id)).where(
Alert.severity == AlertSeverity.WARNING,
Alert.status == AlertStatus.ACTIVE,
)
info_query = select(func.count(Alert.id)).where(
Alert.severity == AlertSeverity.INFO,
Alert.status == AlertStatus.ACTIVE,
)
critical_result = await db.execute(critical_query)
warning_result = await db.execute(warning_query)
info_result = await db.execute(info_query)
return {
"critical": critical_result.scalar() or 0,
"warning": warning_result.scalar() or 0,
"info": info_result.scalar() or 0,
}