feat: add admin seed endpoint for demo data
This commit is contained in:
227
backend/app/api/admin.py
Normal file
227
backend/app/api/admin.py
Normal file
@@ -0,0 +1,227 @@
|
||||
"""Admin/seed endpoints for demo"""
|
||||
from fastapi import APIRouter, Depends, BackgroundTasks
|
||||
from sqlalchemy.orm import Session
|
||||
from app.database import get_db
|
||||
from app.models.player import Player, MembershipTier
|
||||
from app.models.court import Court
|
||||
from app.models.booking import Booking, BookingStatus
|
||||
from app.models.match import Match, MatchPlayer, MatchStage, MatchStatus, MatchType
|
||||
from app.models.tournament import Tournament, TournamentEntry, TournamentMatch, TournamentStatus, BracketType, TournamentMatchStatus
|
||||
from datetime import datetime, timedelta
|
||||
import random
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
|
||||
|
||||
@router.post("/seed")
|
||||
def run_seed(db: Session = Depends(get_db)):
|
||||
"""Run demo seed data"""
|
||||
try:
|
||||
import sys
|
||||
sys.path.insert(0, '/app')
|
||||
from seed import main
|
||||
main()
|
||||
return {"status": "ok", "message": "Seed complete"}
|
||||
except Exception as e:
|
||||
return {"status": "error", "message": str(e)}
|
||||
|
||||
|
||||
@router.post("/update-elos")
|
||||
def update_elos(db: Session = Depends(get_db)):
|
||||
"""Update demo player ELO ratings to proper values"""
|
||||
elo_map = {
|
||||
"marco@demo.com": (1850, MembershipTier.ELITE, 45, 8, "#EF4444"),
|
||||
"sofia@demo.com": (1720, MembershipTier.ELITE, 38, 12, "#EC4899"),
|
||||
"carlos@demo.com": (1630, MembershipTier.PLATINUM, 32, 15, "#8B5CF6"),
|
||||
"ana@demo.com": (1580, MembershipTier.PLATINUM, 28, 18, "#06B6D4"),
|
||||
"juan@demo.com": (1450, MembershipTier.GOLD, 22, 20, "#F59E0B"),
|
||||
"maria@demo.com": (1380, MembershipTier.GOLD, 18, 22, "#10B981"),
|
||||
"pedro@demo.com": (1250, MembershipTier.SILVER, 14, 19, "#3B82F6"),
|
||||
"rosa@demo.com": (1190, MembershipTier.SILVER, 11, 21, "#F97316"),
|
||||
"diego@demo.com": (1100, MembershipTier.SILVER, 9, 18, "#84CC16"),
|
||||
"lucia@demo.com": (980, MembershipTier.BRONZE, 6, 20, "#14B8A6"),
|
||||
"miguel@demo.com": (920, MembershipTier.BRONZE, 4, 15, "#6366F1"),
|
||||
"isabella@demo.com": (850, MembershipTier.BRONZE, 2, 12, "#D946EF"),
|
||||
}
|
||||
|
||||
updated = []
|
||||
for email, (elo, tier, wins, losses, color) in elo_map.items():
|
||||
p = db.query(Player).filter(Player.email == email).first()
|
||||
if p:
|
||||
p.elo_rating = elo
|
||||
p.membership_tier = tier
|
||||
p.wins = wins
|
||||
p.losses = losses
|
||||
p.total_matches = wins + losses
|
||||
p.avatar_color = color
|
||||
updated.append(p.name)
|
||||
|
||||
db.commit()
|
||||
|
||||
# Create courts if not exist
|
||||
if db.query(Court).count() == 0:
|
||||
courts_data = [
|
||||
("Court 1", 1, 200.0, "Sport Court", "LED Lighting, Pro Net System"),
|
||||
("Court 2", 2, 200.0, "Sport Court", "LED Lighting, Spectator Seating"),
|
||||
("Court 3", 3, 250.0, "Cushioned", "Tournament Grade, Scoreboards"),
|
||||
("Court 4", 4, 250.0, "Cushioned", "Tournament Grade, VIP Lounge Access"),
|
||||
]
|
||||
for name, num, rate, surface, features in courts_data:
|
||||
c = Court(name=name, court_number=num, hourly_rate=rate, surface_type=surface, features=features)
|
||||
db.add(c)
|
||||
db.commit()
|
||||
|
||||
# Create active matches
|
||||
courts = db.query(Court).order_by(Court.court_number).all()
|
||||
players = db.query(Player).order_by(Player.elo_rating.desc()).all()
|
||||
|
||||
if db.query(Match).count() == 0 and len(players) >= 4 and len(courts) >= 2:
|
||||
# Active match 1
|
||||
m1 = Match(
|
||||
court_id=courts[0].id,
|
||||
stage=MatchStage.OPEN,
|
||||
match_type=MatchType.DOUBLES,
|
||||
status=MatchStatus.IN_PROGRESS,
|
||||
title="Open Doubles - Court 1",
|
||||
max_players=4,
|
||||
team1_score=7,
|
||||
team2_score=5,
|
||||
started_at=datetime.utcnow() - timedelta(minutes=25),
|
||||
)
|
||||
db.add(m1)
|
||||
db.flush()
|
||||
for pid, team in [(players[0].id, 1), (players[1].id, 1), (players[2].id, 2), (players[3].id, 2)]:
|
||||
db.add(MatchPlayer(match_id=m1.id, player_id=pid, team=team, elo_before=db.query(Player).filter(Player.id == pid).first().elo_rating))
|
||||
|
||||
# Active match 2 (skill-based)
|
||||
m2 = Match(
|
||||
court_id=courts[1].id,
|
||||
stage=MatchStage.SKILL_BASED,
|
||||
match_type=MatchType.DOUBLES,
|
||||
status=MatchStatus.IN_PROGRESS,
|
||||
title="Skill Match - Gold League",
|
||||
max_players=4,
|
||||
min_elo=1200,
|
||||
max_elo=1600,
|
||||
team1_score=3,
|
||||
team2_score=6,
|
||||
started_at=datetime.utcnow() - timedelta(minutes=15),
|
||||
)
|
||||
db.add(m2)
|
||||
db.flush()
|
||||
for pid, team in [(players[4].id, 1), (players[5].id, 1), (players[6].id, 2), (players[7].id, 2)]:
|
||||
db.add(MatchPlayer(match_id=m2.id, player_id=pid, team=team, elo_before=db.query(Player).filter(Player.id == pid).first().elo_rating))
|
||||
|
||||
# Lobby matches
|
||||
m3 = Match(stage=MatchStage.OPEN, match_type=MatchType.DOUBLES, status=MatchStatus.LOBBY,
|
||||
title="Evening Open Game", max_players=4)
|
||||
db.add(m3)
|
||||
db.flush()
|
||||
db.add(MatchPlayer(match_id=m3.id, player_id=players[8].id, team=1, elo_before=players[8].elo_rating))
|
||||
|
||||
m4 = Match(stage=MatchStage.SKILL_BASED, match_type=MatchType.DOUBLES, status=MatchStatus.LOBBY,
|
||||
title="Gold Tier Challenge", max_players=4, min_elo=1200, max_elo=1600)
|
||||
db.add(m4)
|
||||
db.flush()
|
||||
db.add(MatchPlayer(match_id=m4.id, player_id=players[4].id, team=1, elo_before=players[4].elo_rating))
|
||||
db.commit()
|
||||
|
||||
# Create tournament
|
||||
if db.query(Tournament).count() == 0 and len(players) >= 8 and len(courts) >= 3:
|
||||
t = Tournament(
|
||||
name="ServeSync Grand Prix - March 2024",
|
||||
status=TournamentStatus.IN_PROGRESS,
|
||||
max_participants=8,
|
||||
current_round=2,
|
||||
started_at=datetime.utcnow() - timedelta(hours=2),
|
||||
)
|
||||
db.add(t)
|
||||
db.flush()
|
||||
|
||||
tp = players[:8]
|
||||
entries = []
|
||||
for i, player in enumerate(tp):
|
||||
entry = TournamentEntry(tournament_id=t.id, player_id=player.id, seed=i+1, wins=0, losses=0)
|
||||
db.add(entry)
|
||||
entries.append(entry)
|
||||
db.flush()
|
||||
|
||||
r1 = [(tp[0].id, tp[7].id, 11, 5), (tp[1].id, tp[6].id, 11, 7),
|
||||
(tp[2].id, tp[5].id, 8, 11), (tp[3].id, tp[4].id, 11, 9)]
|
||||
|
||||
winners = []
|
||||
losers = []
|
||||
for i, (p1, p2, s1, s2) in enumerate(r1):
|
||||
tm = TournamentMatch(tournament_id=t.id, round_number=1, match_number=i+1,
|
||||
bracket_type=BracketType.WINNERS, status=TournamentMatchStatus.COMPLETED,
|
||||
player1_id=p1, player2_id=p2, team1_score=s1, team2_score=s2,
|
||||
winner_team=1 if s1>s2 else 2,
|
||||
completed_at=datetime.utcnow() - timedelta(hours=1, minutes=30))
|
||||
db.add(tm)
|
||||
w = p1 if s1>s2 else p2
|
||||
l = p2 if s1>s2 else p1
|
||||
winners.append(w)
|
||||
losers.append(l)
|
||||
for e in entries:
|
||||
if e.player_id == w: e.wins += 1
|
||||
elif e.player_id == l:
|
||||
e.losses += 1
|
||||
e.is_in_losers = True
|
||||
|
||||
# R2 winners - 1 completed, 1 active
|
||||
wm1 = TournamentMatch(tournament_id=t.id, round_number=2, match_number=1,
|
||||
bracket_type=BracketType.WINNERS, status=TournamentMatchStatus.COMPLETED,
|
||||
player1_id=winners[0], player2_id=winners[1], team1_score=11, team2_score=8,
|
||||
winner_team=1, completed_at=datetime.utcnow() - timedelta(minutes=45))
|
||||
db.add(wm1)
|
||||
for e in entries:
|
||||
if e.player_id == winners[0]: e.wins += 1
|
||||
elif e.player_id == winners[1]:
|
||||
e.losses += 1
|
||||
e.is_in_losers = True
|
||||
|
||||
wm2 = TournamentMatch(tournament_id=t.id, round_number=2, match_number=2,
|
||||
bracket_type=BracketType.WINNERS, status=TournamentMatchStatus.IN_PROGRESS,
|
||||
player1_id=winners[2], player2_id=winners[3], team1_score=6, team2_score=7)
|
||||
db.add(wm2)
|
||||
|
||||
# Losers bracket
|
||||
lb1 = TournamentMatch(tournament_id=t.id, round_number=1, match_number=1,
|
||||
bracket_type=BracketType.LOSERS, status=TournamentMatchStatus.COMPLETED,
|
||||
player1_id=losers[0], player2_id=losers[1], team1_score=9, team2_score=11,
|
||||
winner_team=2, completed_at=datetime.utcnow() - timedelta(minutes=90))
|
||||
db.add(lb1)
|
||||
lb2 = TournamentMatch(tournament_id=t.id, round_number=1, match_number=2,
|
||||
bracket_type=BracketType.LOSERS, status=TournamentMatchStatus.COMPLETED,
|
||||
player1_id=losers[2], player2_id=losers[3], team1_score=11, team2_score=6,
|
||||
winner_team=1, completed_at=datetime.utcnow() - timedelta(minutes=60))
|
||||
db.add(lb2)
|
||||
|
||||
for e in entries:
|
||||
if e.player_id == losers[0]:
|
||||
e.losses += 1
|
||||
e.is_eliminated = True
|
||||
e.final_rank = 8
|
||||
elif e.player_id == losers[3]:
|
||||
e.losses += 1
|
||||
e.is_eliminated = True
|
||||
e.final_rank = 7
|
||||
|
||||
# Tournament match on court 3
|
||||
p_name_2 = db.query(Player).filter(Player.id == winners[2]).first().name
|
||||
p_name_3 = db.query(Player).filter(Player.id == winners[3]).first().name
|
||||
m_tour = Match(
|
||||
court_id=courts[2].id, stage=MatchStage.TOURNAMENT, match_type=MatchType.SINGLES,
|
||||
status=MatchStatus.IN_PROGRESS,
|
||||
title=f"Tournament R2 - {p_name_2} vs {p_name_3}",
|
||||
max_players=2, team1_score=6, team2_score=7,
|
||||
started_at=datetime.utcnow() - timedelta(minutes=20),
|
||||
)
|
||||
db.add(m_tour)
|
||||
db.flush()
|
||||
for pid, team in [(winners[2], 1), (winners[3], 2)]:
|
||||
db.add(MatchPlayer(match_id=m_tour.id, player_id=pid, team=team,
|
||||
elo_before=db.query(Player).filter(Player.id == pid).first().elo_rating))
|
||||
db.commit()
|
||||
|
||||
return {"status": "ok", "updated": updated, "players": len(updated)}
|
||||
@@ -15,7 +15,7 @@ booking.Base.metadata.create_all(bind=engine)
|
||||
match.Base.metadata.create_all(bind=engine)
|
||||
tournament.Base.metadata.create_all(bind=engine)
|
||||
|
||||
from app.api import players, courts, matches, tournaments, screen
|
||||
from app.api import players, courts, matches, tournaments, screen, admin
|
||||
|
||||
app = FastAPI(
|
||||
title="ServeSync API",
|
||||
@@ -37,6 +37,7 @@ app.include_router(courts.router, prefix="/api")
|
||||
app.include_router(matches.router, prefix="/api")
|
||||
app.include_router(tournaments.router, prefix="/api")
|
||||
app.include_router(screen.router, prefix="/api")
|
||||
app.include_router(admin.router, prefix="/api")
|
||||
|
||||
|
||||
# WebSocket connection manager
|
||||
|
||||
Reference in New Issue
Block a user