fix(user): missing the first entry

This commit is contained in:
MingxuanGame
2026-01-03 16:37:55 +08:00
parent 282eda3250
commit 1c3b309804

View File

@@ -1,4 +1,5 @@
from datetime import timedelta from datetime import datetime, timedelta
import sys
from typing import Annotated, Literal from typing import Annotated, Literal
from app.config import settings from app.config import settings
@@ -141,20 +142,39 @@ async def get_users(
async def get_user_events( async def get_user_events(
session: Database, session: Database,
user_id: Annotated[int, Path(description="用户 ID")], user_id: Annotated[int, Path(description="用户 ID")],
limit: Annotated[int | None, Query(description="限制返回的活动数量")] = None, limit: Annotated[int, Query(description="限制返回的活动数量")] = 50,
offset: Annotated[int | None, Query(description="活动日志的偏移量")] = None, offset: Annotated[int | None, Query(description="活动日志的偏移量")] = None,
current_user: User | None = Security(get_optional_user, scopes=["public"]), current_user: User | None = Security(get_optional_user, scopes=["public"]),
): ):
db_user = await session.get(User, user_id) db_user = await session.get(User, user_id)
if db_user is None or not await visible_to_current_user(db_user, current_user, session): if db_user is None or not await visible_to_current_user(db_user, current_user, session):
raise HTTPException(404, "User Not found") raise HTTPException(404, "User Not found")
if offset is None:
offset = 0
if limit > 100:
limit = 100
if offset == 0:
cursor = sys.maxsize
else:
cursor = (
await session.exec(
select(Event.id)
.where(Event.user_id == db_user.id, Event.created_at >= utcnow() - timedelta(days=30))
.order_by(col(Event.id).desc())
.limit(1)
.offset(offset - 1)
)
).first()
if cursor is None:
return []
events = ( events = (
await session.exec( await session.exec(
select(Event) select(Event)
.where(Event.user_id == db_user.id, Event.created_at >= utcnow() - timedelta(days=30)) .where(Event.user_id == db_user.id, Event.created_at >= utcnow() - timedelta(days=30), Event.id < cursor)
.order_by(col(Event.created_at).desc()) .order_by(col(Event.id).desc())
.limit(limit) .limit(limit)
.offset(offset)
) )
).all() ).all()
return events return events
@@ -434,17 +454,24 @@ async def get_user_beatmapsets(
resp = [] resp = []
elif type == BeatmapsetType.FAVOURITE: elif type == BeatmapsetType.FAVOURITE:
cursor = ( if offset == 0:
await session.exec( cursor = sys.maxsize
select(FavouriteBeatmapset.id).where(FavouriteBeatmapset.user_id == user_id).limit(1).offset(offset) else:
) cursor = (
).first() await session.exec(
select(FavouriteBeatmapset.id)
.where(FavouriteBeatmapset.user_id == user_id)
.order_by(col(FavouriteBeatmapset.id).desc())
.limit(1)
.offset(offset - 1)
)
).first()
if cursor is None: if cursor is None:
return [] return []
favourites = ( favourites = (
await session.exec( await session.exec(
select(FavouriteBeatmapset) select(FavouriteBeatmapset)
.where(FavouriteBeatmapset.user_id == user_id, FavouriteBeatmapset.id > cursor) .where(FavouriteBeatmapset.user_id == user_id, FavouriteBeatmapset.id < cursor)
.order_by(col(FavouriteBeatmapset.id).desc()) .order_by(col(FavouriteBeatmapset.id).desc())
.limit(limit) .limit(limit)
) )
@@ -457,15 +484,18 @@ async def get_user_beatmapsets(
] ]
elif type == BeatmapsetType.MOST_PLAYED: elif type == BeatmapsetType.MOST_PLAYED:
cursor = ( if offset == 0:
await session.exec( cursor = sys.maxsize, sys.maxsize
select(BeatmapPlaycounts.playcount, BeatmapPlaycounts.id) else:
.where(BeatmapPlaycounts.user_id == user_id) cursor = (
.order_by(col(BeatmapPlaycounts.playcount).desc(), col(BeatmapPlaycounts.id).desc()) await session.exec(
.limit(1) select(BeatmapPlaycounts.playcount, BeatmapPlaycounts.id)
.offset(offset) .where(BeatmapPlaycounts.user_id == user_id)
) .order_by(col(BeatmapPlaycounts.playcount).desc(), col(BeatmapPlaycounts.id).desc())
).first() .limit(1)
.offset(offset - 1)
)
).first()
if cursor is None: if cursor is None:
return [] return []
cursor_pc, cursor_id = cursor cursor_pc, cursor_id = cursor
@@ -509,7 +539,6 @@ async def get_user_beatmapsets(
) )
@asset_proxy_response @asset_proxy_response
async def get_user_scores( async def get_user_scores(
request: Request,
session: Database, session: Database,
api_version: APIVersion, api_version: APIVersion,
background_task: BackgroundTasks, background_task: BackgroundTasks,
@@ -550,15 +579,18 @@ async def get_user_scores(
scores = [] scores = []
if type == "pinned": if type == "pinned":
where_clause &= Score.pinned_order > 0 where_clause &= Score.pinned_order > 0
cursor = ( if offset == 0:
await session.exec( cursor = 0, sys.maxsize
select(Score.pinned_order, Score.id) else:
.where(where_clause) cursor = (
.order_by(col(Score.pinned_order).asc(), col(Score.id).desc()) await session.exec(
.limit(1) select(Score.pinned_order, Score.id)
.offset(offset) .where(where_clause)
) .order_by(col(Score.pinned_order).asc(), col(Score.id).desc())
).first() .limit(1)
.offset(offset - 1)
)
).first()
if cursor: if cursor:
cursor_pinned, cursor_id = cursor cursor_pinned, cursor_id = cursor
where_clause &= (col(Score.pinned_order) > cursor_pinned) | ( where_clause &= (col(Score.pinned_order) > cursor_pinned) | (
@@ -576,15 +608,19 @@ async def get_user_scores(
elif type == "best": elif type == "best":
where_clause &= exists().where(col(BestScore.score_id) == Score.id) where_clause &= exists().where(col(BestScore.score_id) == Score.id)
includes.append("weight") includes.append("weight")
cursor = (
await session.exec( if offset == 0:
select(Score.pp, Score.id) cursor = sys.maxsize, sys.maxsize
.where(where_clause) else:
.order_by(col(Score.pp).desc(), col(Score.id).desc()) cursor = (
.limit(1) await session.exec(
.offset(offset) select(Score.pp, Score.id)
) .where(where_clause)
).first() .order_by(col(Score.pp).desc(), col(Score.id).desc())
.limit(1)
.offset(offset - 1)
)
).first()
if cursor: if cursor:
cursor_pp, cursor_id = cursor cursor_pp, cursor_id = cursor
where_clause &= tuple_(col(Score.pp), col(Score.id)) < tuple_(cursor_pp, cursor_id) where_clause &= tuple_(col(Score.pp), col(Score.id)) < tuple_(cursor_pp, cursor_id)
@@ -596,15 +632,18 @@ async def get_user_scores(
elif type == "recent": elif type == "recent":
where_clause &= Score.ended_at > utcnow() - timedelta(hours=24) where_clause &= Score.ended_at > utcnow() - timedelta(hours=24)
cursor = ( if offset == 0:
await session.exec( cursor = datetime.max, sys.maxsize
select(Score.ended_at, Score.id) else:
.where(where_clause) cursor = (
.order_by(col(Score.ended_at).desc(), col(Score.id).desc()) await session.exec(
.limit(1) select(Score.ended_at, Score.id)
.offset(offset) .where(where_clause)
) .order_by(col(Score.ended_at).desc(), col(Score.id).desc())
).first() .limit(1)
.offset(offset - 1)
)
).first()
if cursor: if cursor:
cursor_date, cursor_id = cursor cursor_date, cursor_id = cursor
where_clause &= tuple_(col(Score.ended_at), col(Score.id)) < tuple_(cursor_date, cursor_id) where_clause &= tuple_(col(Score.ended_at), col(Score.id)) < tuple_(cursor_date, cursor_id)