From d7002374b620a515c60d0c96da700c237fcd6406 Mon Sep 17 00:00:00 2001 From: MingxuanGame Date: Sat, 9 Aug 2025 04:53:20 +0000 Subject: [PATCH] fix(playlist): fix user attempts --- app/database/__init__.py | 7 +++++- app/database/playlist_attempts.py | 37 +++++++++++++++++++++++++++++ app/database/playlist_best_score.py | 11 +++++---- app/database/room.py | 15 +++++++++++- app/router/room.py | 6 ++++- 5 files changed, 68 insertions(+), 8 deletions(-) diff --git a/app/database/__init__.py b/app/database/__init__.py index 0ee253b..4501e21 100644 --- a/app/database/__init__.py +++ b/app/database/__init__.py @@ -16,7 +16,11 @@ from .lazer_user import ( UserResp, ) from .multiplayer_event import MultiplayerEvent, MultiplayerEventResp -from .playlist_attempts import ItemAttemptsCount, ItemAttemptsResp +from .playlist_attempts import ( + ItemAttemptsCount, + ItemAttemptsResp, + PlaylistAggregateScore, +) from .playlist_best_score import PlaylistBestScore from .playlists import Playlist, PlaylistResp from .pp_best_score import PPBestScore @@ -58,6 +62,7 @@ __all__ = [ "OAuthToken", "PPBestScore", "Playlist", + "PlaylistAggregateScore", "PlaylistBestScore", "PlaylistResp", "Relationship", diff --git a/app/database/playlist_attempts.py b/app/database/playlist_attempts.py index cfd8147..5d580cf 100644 --- a/app/database/playlist_attempts.py +++ b/app/database/playlist_attempts.py @@ -1,6 +1,7 @@ from .lazer_user import User, UserResp from .playlist_best_score import PlaylistBestScore +from pydantic import BaseModel from sqlmodel import ( BigInteger, Column, @@ -112,3 +113,39 @@ class ItemAttemptsResp(ItemAttemptsCountBase): resp.position = await item_attempts.get_position(session) # resp.accuracy *= 100 return resp + + +class ItemAttemptsCountForItem(BaseModel): + id: int + attempts: int + passed: bool + + +class PlaylistAggregateScore(BaseModel): + playlist_item_attempts: list[ItemAttemptsCountForItem] = Field(default_factory=list) + + @classmethod + async def from_db( + cls, + room_id: int, + user_id: int, + session: AsyncSession, + ) -> "PlaylistAggregateScore": + playlist_scores = ( + await session.exec( + select(PlaylistBestScore).where( + PlaylistBestScore.room_id == room_id, + PlaylistBestScore.user_id == user_id, + ) + ) + ).all() + playlist_item_attempts = [] + for score in playlist_scores: + playlist_item_attempts.append( + ItemAttemptsCountForItem( + id=score.playlist_id, + attempts=score.attempts, + passed=score.score.passed, + ) + ) + return cls(playlist_item_attempts=playlist_item_attempts) diff --git a/app/database/playlist_best_score.py b/app/database/playlist_best_score.py index 46bbfba..6ecb18a 100644 --- a/app/database/playlist_best_score.py +++ b/app/database/playlist_best_score.py @@ -62,20 +62,21 @@ async def process_playlist_best_score( ) ).first() if previous is None: - score = PlaylistBestScore( + previous = PlaylistBestScore( user_id=user_id, score_id=score_id, room_id=room_id, playlist_id=playlist_id, total_score=total_score, ) - session.add(score) - else: + session.add(previous) + elif not previous.score.passed or previous.total_score < total_score: previous.score_id = score_id previous.total_score = total_score - previous.attempts += 1 + previous.attempts += 1 await session.commit() - await redis.decr(f"multiplayer:{room_id}:gameplay:players") + if await redis.exists(f"multiplayer:{room_id}:gameplay:players"): + await redis.decr(f"multiplayer:{room_id}:gameplay:players") async def get_position( diff --git a/app/database/room.py b/app/database/room.py index a478f16..7fb18fa 100644 --- a/app/database/room.py +++ b/app/database/room.py @@ -1,5 +1,6 @@ from datetime import UTC, datetime +from app.database.playlist_attempts import PlaylistAggregateScore from app.models.model import UTCBaseModel from app.models.multiplayer_hub import ServerMultiplayerRoom from app.models.room import ( @@ -23,6 +24,7 @@ from sqlmodel import ( Relationship, SQLModel, ) +from sqlmodel.ext.asyncio.session import AsyncSession class RoomBase(SQLModel, UTCBaseModel): @@ -77,9 +79,16 @@ class RoomResp(RoomBase): playlist_item_stats: RoomPlaylistItemStats | None = None difficulty_range: RoomDifficultyRange | None = None current_playlist_item: PlaylistResp | None = None + current_user_score: PlaylistAggregateScore | None = None @classmethod - async def from_db(cls, room: Room) -> "RoomResp": + async def from_db( + cls, + room: Room, + include: list[str] = [], + session: AsyncSession | None = None, + user: User | None = None, + ) -> "RoomResp": resp = cls.model_validate(room.model_dump()) stats = RoomPlaylistItemStats(count_active=0, count_total=0) @@ -105,6 +114,10 @@ class RoomResp(RoomBase): resp.difficulty_range = difficulty_range resp.current_playlist_item = resp.playlist[-1] if resp.playlist else None + if "current_user_score" in include and user and session: + resp.current_user_score = await PlaylistAggregateScore.from_db( + room.id, user.id, session + ) return resp @classmethod diff --git a/app/router/room.py b/app/router/room.py index b4d77e2..8c35081 100644 --- a/app/router/room.py +++ b/app/router/room.py @@ -116,13 +116,17 @@ async def get_room( room: int, category: str = Query(default=""), db: AsyncSession = Depends(get_db), + current_user: User = Depends(get_current_user), redis: Redis = Depends(get_redis), ): # 直接从db获取信息,毕竟都一样 db_room = (await db.exec(select(Room).where(Room.id == room))).first() if db_room is None: raise HTTPException(404, "Room not found") - return await RoomResp.from_db(db_room) + resp = await RoomResp.from_db( + db_room, include=["current_user_score"], session=db, user=current_user + ) + return resp @router.delete("/rooms/{room}", tags=["room"])