diff --git a/database.py b/database.py index 6549e7d..0c6f6a5 100644 --- a/database.py +++ b/database.py @@ -1,4 +1,4 @@ -from sqlalchemy import create_engine, Column, String, Integer, Boolean, DateTime, ForeignKey, Text, BigInteger +from sqlalchemy import create_engine, Column, String, Integer, Boolean, DateTime, ForeignKey, Text, BigInteger, Float, func from sqlalchemy.orm import declarative_base, sessionmaker from sqlalchemy.exc import OperationalError from config import settings @@ -45,6 +45,20 @@ class EquipmentLast(Base): Rank = Column(Integer) Udemae = Column(Integer) +class PlayerRank(Base): + __tablename__ = 'player_ranks' + + PId = Column(BigInteger, primary_key=True, nullable=False) + GameMode = Column(Integer, primary_key=True, nullable=False) + MiiName = Column(String, nullable=True) + Rank = Column(Integer, default=0) + FesPower = Column(Float, default=0.0) + WinSum = Column(Integer, default=0) + LoseSum = Column(Integer, default=0) + RankingScore = Column(Float, default=0.0) + createdAt = Column(DateTime, server_default=func.now()) + updatedAt = Column(DateTime, onupdate=func.now()) + engine = create_engine(settings.db_url, pool_pre_ping=True) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) diff --git a/main.py b/main.py index b4d38d2..e52d154 100644 --- a/main.py +++ b/main.py @@ -11,6 +11,7 @@ from routes import me from routes.equipment import equipment_history from routes.equipment import equipment from services.boss_retrieval import process_boss_file +from routes import Ranking from contextlib import asynccontextmanager import asyncio import subprocess @@ -119,6 +120,7 @@ app.include_router(boss.router, prefix="/api/v1") app.include_router(me.router, prefix="/api/v1") app.include_router(equipment_history.router, prefix="/api/v1") app.include_router(equipment.router, prefix="/api/v1") +app.include_router(Ranking.router, prefix="/api/v1") if __name__ == '__main__': uvicorn.run("main:app", host="0.0.0.0", port=settings.port, reload=True) \ No newline at end of file diff --git a/routes/Ranking.py b/routes/Ranking.py new file mode 100644 index 0000000..2e39f8b --- /dev/null +++ b/routes/Ranking.py @@ -0,0 +1,57 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import Session as DBSession +from sqlalchemy import desc +from database import SessionLocal, PlayerRank + +router = APIRouter() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +@router.get("/leaderboard") +async def get_leaderboard(db: DBSession = Depends(get_db)): + try: + top_100_query = ( + db.query(PlayerRank.PId) + .order_by(desc(PlayerRank.FesPower)) + .limit(100) + .all() + ) + top_100_pids = {row for row in top_100_query} + modes = [0, 1, 2] + + leaderboard = {} + + for mode in modes: + top_players = ( + db.query(PlayerRank) + .filter(PlayerRank.GameMode == mode) + .order_by(desc(PlayerRank.RankingScore)) + .limit(9) + .all() + ) + + mode_results = [] + for player in top_players: + mode_results.append({ + "PId": player.PId, + "MiiName": player.MiiName, + "Rank": player.Rank, + "WinSum": player.WinSum, + "LoseSum": player.LoseSum, + "RankingScore": round(player.RankingScore, 2), + "FesPower": player.FesPower, + "is_top_100_fes": player.PId in top_100_pids + }) + + leaderboard[f"mode_{mode}"] = mode_results + + return leaderboard + + except Exception as e: + print(f"Error fetching leaderboard: {e}") + return {"error": str(e)} \ No newline at end of file