Refactor room participant and password handling

Replaces ORM object updates with SQLAlchemy update statements for participant and room records, improving efficiency. Enhances room password verification logic and request body parsing in add_user_to_room, adds debug logging, and simplifies error handling. Removes unused user_data parameter and streamlines participant removal.
This commit is contained in:
咕谷酱
2025-08-23 21:39:40 +08:00
committed by MingxuanGame
parent 8e6b462645
commit 403d395ccc

View File

@@ -6,7 +6,8 @@ from typing import Any, Dict, List
from fastapi import APIRouter, HTTPException, Request, status
from pydantic import BaseModel
from sqlmodel import col, select
from sqlmodel import col, select, desc
from sqlalchemy import update
from app.database.lazer_user import User
from app.database.playlists import Playlist as DBPlaylist
@@ -234,49 +235,69 @@ async def _update_room_participant_count(db: Database, room_id: int) -> None:
)
count = len(active_participants.all())
# Update room participant count
room_result = await db.execute(select(Room).where(Room.id == room_id))
room_obj = room_result.scalar_one_or_none()
if room_obj:
room_obj.participant_count = count
# Update room participant count using SQLAlchemy update statement
await db.execute(
update(Room)
.where(col(Room.id) == room_id)
.values(participant_count=count)
)
async def _verify_room_password(db: Database, room_id: int, provided_password: str | None) -> None:
"""Verify room password if required."""
room_result = await db.execute(
select(Room.password).where(Room.id == room_id)
select(Room).where(col(Room.id) == room_id)
)
room_password = room_result.scalar_one_or_none()
room = room_result.scalar_one_or_none()
if room_password is None:
if room is None:
print(f"Room {room_id} not found")
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Room not found"
)
if room_password and provided_password != room_password:
print(f"Room {room_id} has password: {bool(room.password)}, provided: {bool(provided_password)}")
# If room has password but none provided
if room.password and not provided_password:
print(f"Room {room_id} requires password but none provided")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Password required"
)
# If room has password and provided password doesn't match
if room.password and provided_password and provided_password != room.password:
print(f"Room {room_id} password mismatch")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid password"
)
print(f"Room {room_id} password verification passed")
async def _add_or_update_participant(db: Database, room_id: int, user_id: int) -> None:
"""Add a user as participant or update existing participation."""
# Check if user already has a participation record
existing_result = await db.execute(
select(RoomParticipatedUser).where(
select(RoomParticipatedUser.id).where(
RoomParticipatedUser.room_id == room_id,
RoomParticipatedUser.user_id == user_id
)
).order_by(desc(RoomParticipatedUser.joined_at))
)
existing = existing_result.scalar_one_or_none()
existing_id = existing_result.scalar_one_or_none()
if existing:
# Rejoin room
existing.left_at = None
existing.joined_at = utcnow()
if existing_id:
# Update existing participation record using SQLAlchemy update
await db.execute(
update(RoomParticipatedUser)
.where(col(RoomParticipatedUser.id) == existing_id)
.values(left_at=None, joined_at=utcnow())
)
else:
# New participant
# Create new participation record
participant = RoomParticipatedUser(room_id=room_id, user_id=user_id)
db.add(participant)
@@ -346,39 +367,53 @@ async def add_user_to_room(
room_id: int,
user_id: int,
db: Database,
user_data: Dict[str, Any] | None = None,
timestamp: str = "",
) -> Dict[str, Any]:
"""Add a user to a multiplayer room."""
try:
# Verify request signature
body = await request.body()
if not verify_request_signature(request, timestamp, body):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid request signature"
)
#try:
print(f"Adding user {user_id} to room {room_id}")
# Get request body and parse user_data
body = await request.body()
user_data = None
if body:
try:
user_data = json.loads(body.decode('utf-8'))
print(f"Parsed user_data: {user_data}")
except json.JSONDecodeError:
print("Failed to parse user_data from request body")
user_data = None
# Verify request signature
if not verify_request_signature(request, timestamp, body):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid request signature"
)
# Verify room password if provided
provided_password = user_data.get("password") if user_data else None
await _verify_room_password(db, room_id, provided_password)
# Verify room exists and check password
provided_password = user_data.get("password") if user_data else None
print(f"Verifying room {room_id} with password: {provided_password}")
await _verify_room_password(db, room_id, provided_password)
# Add or update participant
await _add_or_update_participant(db, room_id, user_id)
# Update participant count
await _update_room_participant_count(db, room_id)
await db.commit()
return {"success": True}
# Add or update participant
await _add_or_update_participant(db, room_id, user_id)
# Update participant count
await _update_room_participant_count(db, room_id)
await db.commit()
print(f"Successfully added user {user_id} to room {room_id}")
return {"success": True}
except HTTPException:
""" except HTTPException:
raise
except Exception as e:
print(f"Error adding user to room: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to add user to room: {str(e)}"
)
) """
@router.delete("/multiplayer/rooms/{room_id}/users/{user_id}")
@@ -399,18 +434,16 @@ async def remove_user_from_room(
detail="Invalid request signature"
)
# Mark user as left
result = await db.execute(
select(RoomParticipatedUser).where(
RoomParticipatedUser.room_id == room_id,
RoomParticipatedUser.user_id == user_id,
# Mark user as left using SQLAlchemy update statement
await db.execute(
update(RoomParticipatedUser)
.where(
col(RoomParticipatedUser.room_id) == room_id,
col(RoomParticipatedUser.user_id) == user_id,
col(RoomParticipatedUser.left_at).is_(None)
)
.values(left_at=utcnow())
)
participation = result.scalar_one_or_none()
if participation:
participation.left_at = utcnow()
# Update participant count
await _update_room_participant_count(db, room_id)