Add admin stats endpoint for usage tracking
This commit is contained in:
100
backend/app/api/endpoints/admin.py
Normal file
100
backend/app/api/endpoints/admin.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy import select, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.security import get_current_user
|
||||
from app.models.user import User
|
||||
from app.models.playlist import Playlist
|
||||
from app.models.track import Track
|
||||
from app.models.recommendation import Recommendation
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
|
||||
ADMIN_EMAILS = ["chris.ryan@deepcutsai.com"]
|
||||
|
||||
|
||||
@router.get("/stats")
|
||||
async def get_stats(
|
||||
user: User = Depends(get_current_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
if user.email not in ADMIN_EMAILS:
|
||||
raise HTTPException(status_code=403, detail="Admin only")
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
today = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
week_ago = now - timedelta(days=7)
|
||||
month_ago = now - timedelta(days=30)
|
||||
|
||||
# User stats
|
||||
total_users = (await db.execute(select(func.count(User.id)))).scalar() or 0
|
||||
pro_users = (await db.execute(select(func.count(User.id)).where(User.is_pro == True))).scalar() or 0
|
||||
|
||||
# Playlist stats
|
||||
total_playlists = (await db.execute(select(func.count(Playlist.id)))).scalar() or 0
|
||||
total_tracks = (await db.execute(select(func.count(Track.id)))).scalar() or 0
|
||||
|
||||
# Recommendation stats
|
||||
total_recs = (await db.execute(select(func.count(Recommendation.id)))).scalar() or 0
|
||||
recs_today = (await db.execute(
|
||||
select(func.count(Recommendation.id)).where(Recommendation.created_at >= today)
|
||||
)).scalar() or 0
|
||||
recs_this_week = (await db.execute(
|
||||
select(func.count(Recommendation.id)).where(Recommendation.created_at >= week_ago)
|
||||
)).scalar() or 0
|
||||
recs_this_month = (await db.execute(
|
||||
select(func.count(Recommendation.id)).where(Recommendation.created_at >= month_ago)
|
||||
)).scalar() or 0
|
||||
|
||||
saved_recs = (await db.execute(
|
||||
select(func.count(Recommendation.id)).where(Recommendation.saved == True)
|
||||
)).scalar() or 0
|
||||
disliked_recs = (await db.execute(
|
||||
select(func.count(Recommendation.id)).where(Recommendation.disliked == True)
|
||||
)).scalar() or 0
|
||||
|
||||
# Per-user breakdown
|
||||
user_stats_result = await db.execute(
|
||||
select(
|
||||
User.id, User.name, User.email, User.is_pro, User.created_at,
|
||||
func.count(Recommendation.id).label("rec_count"),
|
||||
)
|
||||
.outerjoin(Recommendation, Recommendation.user_id == User.id)
|
||||
.group_by(User.id)
|
||||
.order_by(User.id)
|
||||
)
|
||||
user_breakdown = [
|
||||
{
|
||||
"id": row.id,
|
||||
"name": row.name,
|
||||
"email": row.email,
|
||||
"is_pro": row.is_pro,
|
||||
"created_at": row.created_at.isoformat() if row.created_at else None,
|
||||
"recommendation_count": row.rec_count,
|
||||
}
|
||||
for row in user_stats_result.all()
|
||||
]
|
||||
|
||||
return {
|
||||
"users": {
|
||||
"total": total_users,
|
||||
"pro": pro_users,
|
||||
"free": total_users - pro_users,
|
||||
},
|
||||
"playlists": {
|
||||
"total": total_playlists,
|
||||
"total_tracks": total_tracks,
|
||||
},
|
||||
"recommendations": {
|
||||
"total": total_recs,
|
||||
"today": recs_today,
|
||||
"this_week": recs_this_week,
|
||||
"this_month": recs_this_month,
|
||||
"saved": saved_recs,
|
||||
"disliked": disliked_recs,
|
||||
},
|
||||
"user_breakdown": user_breakdown,
|
||||
}
|
||||
Reference in New Issue
Block a user