from typing import List from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from sqlalchemy import desc, func from app.db.session import get_db from app.models.monitor import Monitor, UptimeCheck from app.models.schemas import ( MonitorCreate, MonitorUpdate, MonitorResponse, UptimeCheckResponse, MonitorStats, ) router = APIRouter(prefix="/monitors", tags=["monitors"]) @router.post("/", response_model=MonitorResponse) def create_monitor(monitor: MonitorCreate, db: Session = Depends(get_db)): db_monitor = Monitor(**monitor.dict()) db.add(db_monitor) db.commit() db.refresh(db_monitor) return db_monitor @router.get("/", response_model=List[MonitorResponse]) def get_monitors(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): monitors = db.query(Monitor).offset(skip).limit(limit).all() return monitors @router.get("/{monitor_id}", response_model=MonitorResponse) def get_monitor(monitor_id: int, db: Session = Depends(get_db)): monitor = db.query(Monitor).filter(Monitor.id == monitor_id).first() if not monitor: raise HTTPException(status_code=404, detail="Monitor not found") return monitor @router.put("/{monitor_id}", response_model=MonitorResponse) def update_monitor( monitor_id: int, monitor: MonitorUpdate, db: Session = Depends(get_db) ): db_monitor = db.query(Monitor).filter(Monitor.id == monitor_id).first() if not db_monitor: raise HTTPException(status_code=404, detail="Monitor not found") update_data = monitor.dict(exclude_unset=True) for field, value in update_data.items(): setattr(db_monitor, field, value) db.commit() db.refresh(db_monitor) return db_monitor @router.delete("/{monitor_id}") def delete_monitor(monitor_id: int, db: Session = Depends(get_db)): monitor = db.query(Monitor).filter(Monitor.id == monitor_id).first() if not monitor: raise HTTPException(status_code=404, detail="Monitor not found") db.delete(monitor) db.commit() return {"message": "Monitor deleted successfully"} @router.get("/{monitor_id}/checks", response_model=List[UptimeCheckResponse]) def get_monitor_checks( monitor_id: int, skip: int = 0, limit: int = 100, db: Session = Depends(get_db) ): monitor = db.query(Monitor).filter(Monitor.id == monitor_id).first() if not monitor: raise HTTPException(status_code=404, detail="Monitor not found") checks = ( db.query(UptimeCheck) .filter(UptimeCheck.monitor_id == monitor_id) .order_by(desc(UptimeCheck.checked_at)) .offset(skip) .limit(limit) .all() ) return checks @router.get("/{monitor_id}/stats", response_model=MonitorStats) def get_monitor_stats(monitor_id: int, db: Session = Depends(get_db)): monitor = db.query(Monitor).filter(Monitor.id == monitor_id).first() if not monitor: raise HTTPException(status_code=404, detail="Monitor not found") total_checks = ( db.query(UptimeCheck).filter(UptimeCheck.monitor_id == monitor_id).count() ) successful_checks = ( db.query(UptimeCheck) .filter(UptimeCheck.monitor_id == monitor_id, UptimeCheck.is_up) .count() ) uptime_percentage = ( (successful_checks / total_checks * 100) if total_checks > 0 else 0 ) avg_response_time = ( db.query(func.avg(UptimeCheck.response_time)) .filter( UptimeCheck.monitor_id == monitor_id, UptimeCheck.is_up, UptimeCheck.response_time.isnot(None), ) .scalar() ) last_check = ( db.query(UptimeCheck) .filter(UptimeCheck.monitor_id == monitor_id) .order_by(desc(UptimeCheck.checked_at)) .first() ) return MonitorStats( monitor_id=monitor_id, uptime_percentage=round(uptime_percentage, 2), total_checks=total_checks, successful_checks=successful_checks, average_response_time=round(avg_response_time, 2) if avg_response_time else None, last_check=last_check.checked_at if last_check else None, )