101 lines
3.4 KiB
Python
101 lines
3.4 KiB
Python
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,
|
|
}
|