135 lines
4 KiB
Python
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
|
|
]
|