teecup/app/routers/players.py

96 lines
3 KiB
Python
Raw Normal View History

"""
Spillerpool organisasjonsnivå (ADR-001: gjenbrukbar tvers av turneringer).
Kun org-medlemskap kreves (get_authorized_org) å opprette en spiller i poolen
er organisator-arbeid, ikke noe som forutsetter rostring et lag.
Utvidet profil (ADR-017): kontakt-/identitetsfelt brukt til å matche en
selvregistrerende spiller mot en allerede organisator-opprettet rad
e-post (se app/routers/registration.py), og senere til å koble
app_user.id (app/routers/auth.py sin verify_magic_link).
"""
from datetime import date
from fastapi import APIRouter, Depends
from pydantic import BaseModel, EmailStr, Field
from ..auth import get_authorized_org
from ..db import org_connection
from ..errors import translate_db_errors
router = APIRouter()
class PlayerCreate(BaseModel):
display_name: str = Field(min_length=1, max_length=200)
handicap_index: float | None = None
gender: str | None = Field(default=None, pattern="^[mfx]$")
mobile: str | None = None
email: EmailStr | None = None
birth_date: date | None = None
nickname: str | None = None
country: str | None = None
club: str | None = None
club_member_number: str | None = None
class Player(BaseModel):
id: str
display_name: str
handicap_index: float | None
gender: str | None
mobile: str | None
email: str | None
birth_date: date | None
nickname: str | None
country: str | None
club: str | None
club_member_number: str | None
_PLAYER_COLUMNS = """
id::text, display_name, handicap_index::float AS handicap_index, gender,
mobile, email, birth_date, nickname, country, club, club_member_number
"""
@router.get("/orgs/{organization_id}/players", response_model=list[Player])
async def list_players(
organization_id: str = Depends(get_authorized_org),
) -> list[Player]:
async with org_connection(organization_id) as conn:
rows = await conn.fetch(
f"SELECT {_PLAYER_COLUMNS} FROM player ORDER BY display_name"
)
return [Player(**dict(r)) for r in rows]
@router.post("/orgs/{organization_id}/players", response_model=Player, status_code=201)
async def create_player(
body: PlayerCreate,
organization_id: str = Depends(get_authorized_org),
) -> Player:
async with org_connection(organization_id) as conn, translate_db_errors():
row = await conn.fetchrow(
f"""
INSERT INTO player
(organization_id, display_name, handicap_index, gender,
mobile, email, birth_date, nickname, country, club, club_member_number)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
RETURNING {_PLAYER_COLUMNS}
""",
organization_id,
body.display_name,
body.handicap_index,
body.gender,
body.mobile,
body.email.lower() if body.email else None,
body.birth_date,
body.nickname,
body.country,
body.club,
body.club_member_number,
)
return Player(**dict(row))