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:
@@ -6,7 +6,8 @@ from typing import Any, Dict, List
|
|||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, Request, status
|
from fastapi import APIRouter, HTTPException, Request, status
|
||||||
from pydantic import BaseModel
|
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.lazer_user import User
|
||||||
from app.database.playlists import Playlist as DBPlaylist
|
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())
|
count = len(active_participants.all())
|
||||||
|
|
||||||
# Update room participant count
|
# Update room participant count using SQLAlchemy update statement
|
||||||
room_result = await db.execute(select(Room).where(Room.id == room_id))
|
await db.execute(
|
||||||
room_obj = room_result.scalar_one_or_none()
|
update(Room)
|
||||||
if room_obj:
|
.where(col(Room.id) == room_id)
|
||||||
room_obj.participant_count = count
|
.values(participant_count=count)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _verify_room_password(db: Database, room_id: int, provided_password: str | None) -> None:
|
async def _verify_room_password(db: Database, room_id: int, provided_password: str | None) -> None:
|
||||||
"""Verify room password if required."""
|
"""Verify room password if required."""
|
||||||
room_result = await db.execute(
|
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(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail="Room 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(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
detail="Invalid password"
|
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:
|
async def _add_or_update_participant(db: Database, room_id: int, user_id: int) -> None:
|
||||||
"""Add a user as participant or update existing participation."""
|
"""Add a user as participant or update existing participation."""
|
||||||
|
# Check if user already has a participation record
|
||||||
existing_result = await db.execute(
|
existing_result = await db.execute(
|
||||||
select(RoomParticipatedUser).where(
|
select(RoomParticipatedUser.id).where(
|
||||||
RoomParticipatedUser.room_id == room_id,
|
RoomParticipatedUser.room_id == room_id,
|
||||||
RoomParticipatedUser.user_id == user_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:
|
if existing_id:
|
||||||
# Rejoin room
|
# Update existing participation record using SQLAlchemy update
|
||||||
existing.left_at = None
|
await db.execute(
|
||||||
existing.joined_at = utcnow()
|
update(RoomParticipatedUser)
|
||||||
|
.where(col(RoomParticipatedUser.id) == existing_id)
|
||||||
|
.values(left_at=None, joined_at=utcnow())
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# New participant
|
# Create new participation record
|
||||||
participant = RoomParticipatedUser(room_id=room_id, user_id=user_id)
|
participant = RoomParticipatedUser(room_id=room_id, user_id=user_id)
|
||||||
db.add(participant)
|
db.add(participant)
|
||||||
|
|
||||||
@@ -346,39 +367,53 @@ async def add_user_to_room(
|
|||||||
room_id: int,
|
room_id: int,
|
||||||
user_id: int,
|
user_id: int,
|
||||||
db: Database,
|
db: Database,
|
||||||
user_data: Dict[str, Any] | None = None,
|
|
||||||
timestamp: str = "",
|
timestamp: str = "",
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Add a user to a multiplayer room."""
|
"""Add a user to a multiplayer room."""
|
||||||
try:
|
#try:
|
||||||
# Verify request signature
|
print(f"Adding user {user_id} to room {room_id}")
|
||||||
body = await request.body()
|
|
||||||
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
|
# Get request body and parse user_data
|
||||||
provided_password = user_data.get("password") if user_data else None
|
body = await request.body()
|
||||||
await _verify_room_password(db, room_id, provided_password)
|
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
|
||||||
|
|
||||||
# Add or update participant
|
# Verify request signature
|
||||||
await _add_or_update_participant(db, room_id, user_id)
|
if not verify_request_signature(request, timestamp, body):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
|
detail="Invalid request signature"
|
||||||
|
)
|
||||||
|
|
||||||
# Update participant count
|
# Verify room exists and check password
|
||||||
await _update_room_participant_count(db, room_id)
|
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)
|
||||||
|
|
||||||
await db.commit()
|
# Add or update participant
|
||||||
return {"success": True}
|
await _add_or_update_participant(db, room_id, user_id)
|
||||||
|
|
||||||
except HTTPException:
|
# 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:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
print(f"Error adding user to room: {str(e)}")
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
detail=f"Failed to add user to room: {str(e)}"
|
detail=f"Failed to add user to room: {str(e)}"
|
||||||
)
|
) """
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/multiplayer/rooms/{room_id}/users/{user_id}")
|
@router.delete("/multiplayer/rooms/{room_id}/users/{user_id}")
|
||||||
@@ -399,18 +434,16 @@ async def remove_user_from_room(
|
|||||||
detail="Invalid request signature"
|
detail="Invalid request signature"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mark user as left
|
# Mark user as left using SQLAlchemy update statement
|
||||||
result = await db.execute(
|
await db.execute(
|
||||||
select(RoomParticipatedUser).where(
|
update(RoomParticipatedUser)
|
||||||
RoomParticipatedUser.room_id == room_id,
|
.where(
|
||||||
RoomParticipatedUser.user_id == user_id,
|
col(RoomParticipatedUser.room_id) == room_id,
|
||||||
|
col(RoomParticipatedUser.user_id) == user_id,
|
||||||
col(RoomParticipatedUser.left_at).is_(None)
|
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
|
# Update participant count
|
||||||
await _update_room_participant_count(db, room_id)
|
await _update_room_participant_count(db, room_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user