82 lines
3.0 KiB
Python
82 lines
3.0 KiB
Python
from datetime import datetime, timezone, timedelta
|
|
from fastapi import APIRouter, Depends
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, func
|
|
|
|
from app.core.database import get_db
|
|
from app.models.models import Client, BackupJob, BackupSession, User
|
|
from app.schemas.schemas import DashboardStatsResponse
|
|
from app.api.deps import get_current_user
|
|
from app.storage.local import storage_provider
|
|
|
|
router = APIRouter(prefix="/stats", tags=["Dashboard Statistics"])
|
|
|
|
@router.get("", response_model=DashboardStatsResponse)
|
|
async def get_dashboard_stats(
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(get_current_user)
|
|
):
|
|
# Clients aggregation
|
|
total_clients_res = await db.execute(select(func.count(Client.id)).where(Client.is_active == True))
|
|
total_clients = total_clients_res.scalar() or 0
|
|
|
|
# Consider online if last_seen_at was in the last 5 minutes
|
|
cutoff_online = datetime.now(timezone.utc) - timedelta(minutes=5)
|
|
online_clients_res = await db.execute(
|
|
select(func.count(Client.id)).where(
|
|
Client.is_active == True,
|
|
Client.status == "ONLINE",
|
|
Client.last_seen_at >= cutoff_online
|
|
)
|
|
)
|
|
online_clients = online_clients_res.scalar() or 0
|
|
offline_clients = max(0, total_clients - online_clients)
|
|
|
|
# Jobs count
|
|
total_jobs_res = await db.execute(select(func.count(BackupJob.id)).where(BackupJob.is_active == True))
|
|
total_jobs = total_jobs_res.scalar() or 0
|
|
|
|
# Backups today
|
|
today_start = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
|
|
backups_today_res = await db.execute(
|
|
select(func.count(BackupSession.id)).where(BackupSession.started_at >= today_start)
|
|
)
|
|
backups_today = backups_today_res.scalar() or 0
|
|
|
|
backups_success_res = await db.execute(
|
|
select(func.count(BackupSession.id)).where(
|
|
BackupSession.started_at >= today_start,
|
|
BackupSession.status == "SUCCESS"
|
|
)
|
|
)
|
|
backups_success = backups_success_res.scalar() or 0
|
|
|
|
backups_failed_res = await db.execute(
|
|
select(func.count(BackupSession.id)).where(
|
|
BackupSession.started_at >= today_start,
|
|
BackupSession.status == "FAILED"
|
|
)
|
|
)
|
|
backups_failed = backups_failed_res.scalar() or 0
|
|
|
|
# Active uploads
|
|
active_uploads_res = await db.execute(
|
|
select(func.count(BackupSession.id)).where(BackupSession.status.in_(["PENDING", "UPLOADING", "ASSEMBLING"]))
|
|
)
|
|
active_uploads = active_uploads_res.scalar() or 0
|
|
|
|
# Storage metrics
|
|
storage_stats = await storage_provider.get_storage_stats()
|
|
|
|
return {
|
|
"total_clients": total_clients,
|
|
"online_clients": online_clients,
|
|
"offline_clients": offline_clients,
|
|
"total_jobs": total_jobs,
|
|
"backups_today_count": backups_today,
|
|
"backups_today_success": backups_success,
|
|
"backups_today_failed": backups_failed,
|
|
"active_uploads_count": active_uploads,
|
|
"storage": storage_stats
|
|
}
|