from __future__ import annotations from datetime import timedelta from app.database import RankHistory, UserStatistics from app.database.rank_history import RankTop from app.dependencies.database import with_db from app.dependencies.scheduler import get_scheduler from app.models.score import GameMode from app.utils import utcnow from sqlmodel import col, exists, select, update @get_scheduler().scheduled_job("cron", hour=0, minute=0, second=0, id="calculate_user_rank") async def calculate_user_rank(is_today: bool = False): today = utcnow().date() target_date = today if is_today else today - timedelta(days=1) async with with_db() as session: for gamemode in GameMode: users = await session.exec( select(UserStatistics) .where( UserStatistics.mode == gamemode, UserStatistics.pp > 0, col(UserStatistics.is_ranked).is_(True), ) .order_by( col(UserStatistics.pp).desc(), col(UserStatistics.total_score).desc(), ) ) rank = 1 for user in users: is_exist = ( await session.exec( select(exists()).where( RankHistory.user_id == user.user_id, RankHistory.mode == gamemode, RankHistory.date == target_date, ) ) ).first() if not is_exist: rank_history = RankHistory( user_id=user.user_id, mode=gamemode, rank=rank, date=today, ) session.add(rank_history) else: await session.execute( update(RankHistory) .where( col(RankHistory.user_id) == user.user_id, col(RankHistory.mode) == gamemode, col(RankHistory.date) == target_date, ) .values(rank=rank) ) rank_top = ( await session.exec( select(RankTop).where( RankTop.user_id == user.user_id, RankTop.mode == gamemode, ) ) ).first() if not rank_top: rank_top = RankTop( user_id=user.user_id, mode=gamemode, rank=rank, date=today, ) session.add(rank_top) else: if rank_top.rank > rank: rank_top.rank = rank rank_top.date = today rank += 1 await session.commit()