# app/api/v1/admin/notifications.py """ Admin notifications and platform alerts endpoints. Provides endpoints for: - Viewing admin notifications - Managing platform alerts - System health monitoring """ import logging from fastapi import APIRouter, Depends, Query from sqlalchemy.orm import Session from app.api.deps import get_current_admin_api from app.core.database import get_db from app.services.admin_notification_service import ( admin_notification_service, platform_alert_service, ) from models.database.user import User from models.schema.admin import ( AdminNotificationCreate, AdminNotificationListResponse, AdminNotificationResponse, PlatformAlertCreate, PlatformAlertListResponse, PlatformAlertResolve, PlatformAlertResponse, ) from app.modules.messaging.schemas import ( AlertStatisticsResponse, MessageResponse, UnreadCountResponse, ) router = APIRouter(prefix="/notifications") logger = logging.getLogger(__name__) # ============================================================================ # ADMIN NOTIFICATIONS # ============================================================================ @router.get("", response_model=AdminNotificationListResponse) def get_notifications( priority: str | None = Query(None, description="Filter by priority"), notification_type: str | None = Query(None, description="Filter by type"), is_read: bool | None = Query(None, description="Filter by read status"), skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> AdminNotificationListResponse: """Get admin notifications with filtering.""" notifications, total, unread_count = admin_notification_service.get_notifications( db=db, priority=priority, is_read=is_read, notification_type=notification_type, skip=skip, limit=limit, ) return AdminNotificationListResponse( notifications=[ AdminNotificationResponse( id=n.id, type=n.type, priority=n.priority, title=n.title, message=n.message, is_read=n.is_read, read_at=n.read_at, read_by_user_id=n.read_by_user_id, action_required=n.action_required, action_url=n.action_url, metadata=n.notification_metadata, created_at=n.created_at, ) for n in notifications ], total=total, unread_count=unread_count, skip=skip, limit=limit, ) @router.post("", response_model=AdminNotificationResponse) def create_notification( notification_data: AdminNotificationCreate, db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> AdminNotificationResponse: """Create a new admin notification (manual).""" notification = admin_notification_service.create_from_schema( db=db, data=notification_data ) db.commit() logger.info(f"Admin {current_admin.username} created notification: {notification.title}") return AdminNotificationResponse( id=notification.id, type=notification.type, priority=notification.priority, title=notification.title, message=notification.message, is_read=notification.is_read, read_at=notification.read_at, read_by_user_id=notification.read_by_user_id, action_required=notification.action_required, action_url=notification.action_url, metadata=notification.notification_metadata, created_at=notification.created_at, ) @router.get("/recent") def get_recent_notifications( limit: int = Query(5, ge=1, le=10), db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> dict: """Get recent unread notifications for header dropdown.""" notifications = admin_notification_service.get_recent_notifications( db=db, limit=limit ) unread_count = admin_notification_service.get_unread_count(db) return { "notifications": [ { "id": n.id, "type": n.type, "priority": n.priority, "title": n.title, "message": n.message[:100] + "..." if len(n.message) > 100 else n.message, "action_url": n.action_url, "created_at": n.created_at.isoformat(), } for n in notifications ], "unread_count": unread_count, } @router.get("/unread-count", response_model=UnreadCountResponse) def get_unread_count( db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> UnreadCountResponse: """Get count of unread notifications.""" count = admin_notification_service.get_unread_count(db) return UnreadCountResponse(unread_count=count) @router.put("/{notification_id}/read", response_model=MessageResponse) def mark_as_read( notification_id: int, db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> MessageResponse: """Mark notification as read.""" notification = admin_notification_service.mark_as_read( db=db, notification_id=notification_id, user_id=current_admin.id ) db.commit() if notification: return MessageResponse(message="Notification marked as read") return MessageResponse(message="Notification not found") @router.put("/mark-all-read", response_model=MessageResponse) def mark_all_as_read( db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> MessageResponse: """Mark all notifications as read.""" count = admin_notification_service.mark_all_as_read( db=db, user_id=current_admin.id ) db.commit() return MessageResponse(message=f"Marked {count} notifications as read") @router.delete("/{notification_id}", response_model=MessageResponse) def delete_notification( notification_id: int, db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> MessageResponse: """Delete a notification.""" deleted = admin_notification_service.delete_notification( db=db, notification_id=notification_id ) db.commit() if deleted: return MessageResponse(message="Notification deleted") return MessageResponse(message="Notification not found") # ============================================================================ # PLATFORM ALERTS # ============================================================================ @router.get("/alerts", response_model=PlatformAlertListResponse) def get_platform_alerts( severity: str | None = Query(None, description="Filter by severity"), alert_type: str | None = Query(None, description="Filter by alert type"), is_resolved: bool | None = Query(None, description="Filter by resolution status"), skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=100), db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> PlatformAlertListResponse: """Get platform alerts with filtering.""" alerts, total, active_count, critical_count = platform_alert_service.get_alerts( db=db, severity=severity, alert_type=alert_type, is_resolved=is_resolved, skip=skip, limit=limit, ) return PlatformAlertListResponse( alerts=[ PlatformAlertResponse( id=a.id, alert_type=a.alert_type, severity=a.severity, title=a.title, description=a.description, affected_vendors=a.affected_vendors, affected_systems=a.affected_systems, is_resolved=a.is_resolved, resolved_at=a.resolved_at, resolved_by_user_id=a.resolved_by_user_id, resolution_notes=a.resolution_notes, auto_generated=a.auto_generated, occurrence_count=a.occurrence_count, first_occurred_at=a.first_occurred_at, last_occurred_at=a.last_occurred_at, created_at=a.created_at, ) for a in alerts ], total=total, active_count=active_count, critical_count=critical_count, skip=skip, limit=limit, ) @router.post("/alerts", response_model=PlatformAlertResponse) def create_platform_alert( alert_data: PlatformAlertCreate, db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> PlatformAlertResponse: """Create new platform alert (manual).""" alert = platform_alert_service.create_from_schema(db=db, data=alert_data) db.commit() logger.info(f"Admin {current_admin.username} created alert: {alert.title}") return PlatformAlertResponse( id=alert.id, alert_type=alert.alert_type, severity=alert.severity, title=alert.title, description=alert.description, affected_vendors=alert.affected_vendors, affected_systems=alert.affected_systems, is_resolved=alert.is_resolved, resolved_at=alert.resolved_at, resolved_by_user_id=alert.resolved_by_user_id, resolution_notes=alert.resolution_notes, auto_generated=alert.auto_generated, occurrence_count=alert.occurrence_count, first_occurred_at=alert.first_occurred_at, last_occurred_at=alert.last_occurred_at, created_at=alert.created_at, ) @router.put("/alerts/{alert_id}/resolve", response_model=MessageResponse) def resolve_platform_alert( alert_id: int, resolve_data: PlatformAlertResolve, db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> MessageResponse: """Resolve platform alert.""" alert = platform_alert_service.resolve_alert( db=db, alert_id=alert_id, user_id=current_admin.id, resolution_notes=resolve_data.resolution_notes, ) db.commit() if alert: logger.info(f"Admin {current_admin.username} resolved alert {alert_id}") return MessageResponse(message="Alert resolved successfully") return MessageResponse(message="Alert not found or already resolved") @router.get("/alerts/stats", response_model=AlertStatisticsResponse) def get_alert_statistics( db: Session = Depends(get_db), current_admin: User = Depends(get_current_admin_api), ) -> AlertStatisticsResponse: """Get alert statistics for dashboard.""" stats = platform_alert_service.get_statistics(db) return AlertStatisticsResponse(**stats)