Add user ping system and room deletion functionality

Backend changes:
- Fix track deletion foreign key constraint (tracks.py)
  * Clear current_track_id from rooms before deleting track
  * Prevent deletion errors when track is currently playing

- Implement user ping/keepalive system (sync.py, websocket.py, ping_task.py, main.py)
  * Track last pong timestamp for each user
  * Background task sends ping every 30s, disconnects users after 60s timeout
  * Auto-pause playback when room becomes empty
  * Remove disconnected users from room_participants

- Enhance room deletion (rooms.py)
  * Broadcast room_deleted event to all connected users
  * Close all WebSocket connections before deletion
  * Cascade delete participants, queue, and messages

Frontend changes:
- Add ping/pong WebSocket handling (activeRoom.js)
  * Auto-respond to server pings
  * Handle room_deleted event with redirect to home

- Add room deletion UI (RoomView.vue, HomeView.vue, RoomCard.vue)
  * Delete button visible only to room owner
  * Confirmation dialog with warning
  * Delete button on room cards (shows on hover)
  * Redirect to home page after deletion

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-19 20:46:00 +03:00
parent ee8d79d155
commit 0fb16f791d
10 changed files with 398 additions and 9 deletions

View File

@@ -3,12 +3,13 @@ from urllib.parse import quote
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, Request
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from sqlalchemy import select, func, update
from mutagen.mp3 import MP3
from io import BytesIO
from ..database import get_db
from ..models.user import User
from ..models.track import Track
from ..models.room import Room
from ..schemas.track import TrackResponse, TrackWithUrl
from ..services.auth import get_current_user
from ..services.s3 import upload_file, delete_file, generate_presigned_url, can_upload_file, get_file_size, stream_file_chunks
@@ -184,10 +185,17 @@ async def delete_track(
if track.uploaded_by != current_user.id:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not track owner")
# Clear current_track_id from any rooms using this track
await db.execute(
update(Room)
.where(Room.current_track_id == track_id)
.values(current_track_id=None, is_playing=False)
)
# Delete from S3
await delete_file(track.s3_key)
# Delete from DB
# Delete from DB (queue entries will be cascade deleted automatically)
await db.delete(track)
return {"status": "deleted"}