elmeg-demo/backend/routers/leaderboards.py
fullsizemalt 7a549e15ac
Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run
fix(leaderboard): filter out 0xp users
2025-12-24 11:50:17 -08:00

135 lines
4 KiB
Python

from fastapi import APIRouter, Depends, Query
from sqlmodel import Session, select, func, desc
from typing import List, Optional
from database import get_session
from models import Review, Show, Venue, User, Profile, Performance, Song, Rating
router = APIRouter(
prefix="/leaderboards",
tags=["leaderboards"]
)
@router.get("/shows/top")
def get_top_shows(limit: int = 10, session: Session = Depends(get_session)):
"""Get top rated shows based on average rating"""
# Using Rating table allows for more data points than just text reviews
query = (
select(
Show,
Venue,
func.avg(Rating.score).label("avg_score"),
func.count(Rating.id).label("rating_count")
)
.join(Rating, Rating.show_id == Show.id)
.join(Venue, Show.venue_id == Venue.id)
# Rating FK already filters via join
.group_by(Show.id, Venue.id)
.having(func.count(Rating.id) >= 1)
.order_by(desc("avg_score"), desc("rating_count"))
.limit(limit)
)
results = session.exec(query).all()
return [
{
"show": show,
"venue": venue,
"avg_score": round(score, 2) if score else 0,
"review_count": count
}
for show, venue, score, count in results
]
@router.get("/performances/top")
def get_top_performances(limit: int = 20, session: Session = Depends(get_session)):
"""Get top rated performances (Heady Jams)"""
query = (
select(
Performance,
Song,
Show,
Venue,
func.avg(Rating.score).label("avg_score"),
func.count(Rating.id).label("rating_count")
)
.join(Rating, Rating.performance_id == Performance.id)
.join(Song, Performance.song_id == Song.id)
.join(Show, Performance.show_id == Show.id)
.join(Venue, Show.venue_id == Venue.id)
# Rating FK already filters via join
.group_by(Performance.id, Song.id, Show.id, Venue.id)
.having(func.count(Rating.id) >= 1)
.order_by(desc("avg_score"), desc("rating_count"))
.limit(limit)
)
results = session.exec(query).all()
return [
{
"performance": performance,
"song": song,
"show": show,
"venue": venue,
"avg_score": round(score, 2) if score else 0,
"rating_count": count
}
for performance, song, show, venue, score, count in results
]
@router.get("/venues/top")
def get_top_venues(limit: int = 10, session: Session = Depends(get_session)):
"""Get top rated venues based on show ratings there"""
# Aggregate ratings from shows played at each venue
query = (
select(
Venue,
func.avg(Rating.score).label("avg_score"),
func.count(Rating.id).label("rating_count")
)
.join(Show, Show.venue_id == Venue.id)
.join(Rating, Rating.show_id == Show.id)
.group_by(Venue.id)
.having(func.count(Rating.id) >= 1)
.order_by(desc("avg_score"))
.limit(limit)
)
results = session.exec(query).all()
return [
{
"venue": venue,
"avg_score": round(score, 2) if score else 0,
"review_count": count
}
for venue, score, count in results
]
@router.get("/users/active")
def get_active_users(limit: int = 10, session: Session = Depends(get_session)):
"""Get users with most reviews/ratings"""
# Combining reviews count
query = (
select(
Profile,
func.count(Review.id).label("review_count")
)
.join(User, User.id == Profile.user_id)
.join(Review, Review.user_id == User.id)
.where(User.xp > 0)
.group_by(Profile.id)
.order_by(desc("review_count"))
.limit(limit)
)
results = session.exec(query).all()
return [
{
"profile": profile,
"review_count": count
}
for profile, count in results
]