feat(ranking): add global leaderboard

This commit is contained in:
MingxuanGame
2025-08-14 14:35:52 +00:00
parent 155905f652
commit da71d7ce46
3 changed files with 54 additions and 1 deletions

View File

@@ -86,7 +86,7 @@ class UserStatisticsResp(UserStatisticsBase):
@classmethod
async def from_db(
cls, obj: UserStatistics, session: AsyncSession, user_country: str
cls, obj: UserStatistics, session: AsyncSession, user_country: str | None = None
) -> "UserStatisticsResp":
s = cls.model_validate(obj)
s.grade_counts = {

View File

@@ -5,6 +5,7 @@ from . import ( # pyright: ignore[reportUnusedImport] # noqa: F401
beatmapset,
me,
misc,
ranking,
relationship,
room,
score,

52
app/router/v2/ranking.py Normal file
View File

@@ -0,0 +1,52 @@
from __future__ import annotations
from typing import Literal
from app.database import User
from app.database.statistics import UserStatistics, UserStatisticsResp
from app.dependencies import get_current_user
from app.dependencies.database import get_db
from app.models.score import GameMode
from .router import router
from fastapi import Depends, Path, Query, Security
from sqlmodel import col, select
from sqlmodel.ext.asyncio.session import AsyncSession
@router.get(
"/{ruleset}/{type}",
response_model=list[UserStatisticsResp],
name="获取排行榜",
description="获取在指定模式下的用户排行榜",
tags=["排行榜"],
)
async def get_user_ranking(
ruleset: GameMode = Path(..., description="指定 ruleset"),
type: Literal["performance", "score"] = Path(
..., description="排名类型performance 表现分 / score 计分成绩总分"
),
country: str | None = Query(None, description="国家代码"),
page: int = Query(1, ge=1, description="页码"),
current_user: User = Security(get_current_user, scopes=["public"]),
session: AsyncSession = Depends(get_db),
):
wheres = [col(UserStatistics.mode) == ruleset]
if type == "performance":
order_by = col(UserStatistics.pp).desc()
else:
order_by = col(UserStatistics.ranked_score).desc()
if country:
wheres.append(col(UserStatistics.user).has(country_code=country.upper()))
statistics_list = await session.exec(
select(UserStatistics)
.where(*wheres)
.order_by(order_by)
.limit(50)
.offset(50 * (page - 1))
)
return [
await UserStatisticsResp.from_db(statistics, session, None)
for statistics in statistics_list
]