Files
servesync-demo/backend/app/api/tournaments.py
Forge 46fd2953c3 🏓 Initial ServeSync demo build
- FastAPI backend with PostgreSQL + Redis
- 4 core features: Registration, Courts, Matchmaking, Tournament
- Double elimination tournament with bracket visualization
- ELO-based matchmaking (Stage 1 Open, Stage 2 Skill-Based)
- Real-time WebSocket updates
- TV Screen display for courts
- Vue 3 + Tailwind CSS frontend
- Seed data: 12 players, 4 courts, active matches, tournament in progress
- Docker compose stack with Nginx reverse proxy
2026-03-19 00:58:17 +08:00

83 lines
3.0 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app.database import get_db
from app.models.tournament import Tournament, TournamentEntry, TournamentMatch, TournamentStatus
from app.services import tournament as tournament_service
from pydantic import BaseModel
from typing import Optional, List
router = APIRouter(prefix="/tournaments", tags=["tournaments"])
class CreateTournamentRequest(BaseModel):
name: str
max_participants: int = 8
class RegisterPlayerRequest(BaseModel):
player_id: int
class MatchScoreRequest(BaseModel):
team1_score: int
team2_score: int
@router.get("/")
def get_tournaments(db: Session = Depends(get_db)):
tournaments = db.query(Tournament).order_by(Tournament.created_at.desc()).all()
return [
{
"id": t.id,
"name": t.name,
"status": t.status.value,
"max_participants": t.max_participants,
"current_participants": len(t.entries),
"started_at": t.started_at.isoformat() if t.started_at else None,
}
for t in tournaments
]
@router.get("/{tournament_id}")
def get_tournament(tournament_id: int, db: Session = Depends(get_db)):
return tournament_service.get_bracket_data(db, tournament_id)
@router.post("/")
def create_tournament(req: CreateTournamentRequest, db: Session = Depends(get_db)):
t = tournament_service.create_tournament(db, req.name, req.max_participants)
return {"id": t.id, "name": t.name, "status": t.status.value}
@router.post("/{tournament_id}/register")
def register_player(tournament_id: int, req: RegisterPlayerRequest, db: Session = Depends(get_db)):
entry = tournament_service.register_player(db, tournament_id, req.player_id)
if not entry:
raise HTTPException(status_code=400, detail="Cannot register player (tournament full or already registered)")
return {"message": "Registered successfully", "player_id": req.player_id}
@router.post("/{tournament_id}/start")
def start_tournament(tournament_id: int, db: Session = Depends(get_db)):
t = tournament_service.start_tournament(db, tournament_id)
if not t:
raise HTTPException(status_code=400, detail="Cannot start tournament (need at least 4 players)")
return tournament_service.get_bracket_data(db, tournament_id)
@router.post("/{tournament_id}/matches/{match_id}/score")
def complete_tournament_match(
tournament_id: int, match_id: int, req: MatchScoreRequest, db: Session = Depends(get_db)
):
tm = tournament_service.complete_tournament_match(db, match_id, req.team1_score, req.team2_score)
if not tm:
raise HTTPException(status_code=400, detail="Cannot complete match")
return tournament_service.get_bracket_data(db, tournament_id)
@router.get("/{tournament_id}/leaderboard")
def get_leaderboard(tournament_id: int, db: Session = Depends(get_db)):
data = tournament_service.get_bracket_data(db, tournament_id)
return data.get("leaderboard", [])