Files
plm-lottery/app/api/routes/rounds.py
T
davideandClaude Sonnet 5 669c3fb714 Add draw_animation_seconds config and expose winner info during a round
RoundConfig gains draw_animation_seconds (default 20) — the minimum
time the frontend's "estrazione in corso" animation plays before
revealing a winner. It's purely a UI cue: the real draw still waits for
a confirmed block for its entropy (rounds/scheduler.py), which usually
takes much longer than this value, so it only ever extends the
animation, never truncates the real wait.

GET /rounds/current now also returns draw_animation_seconds,
winner_user_id and winner_amount_sats (all populated once the
scheduler sets them on the round, i.e. from "paying_out" onward) so a
client can determine and reveal the outcome. GET /users/me now returns
the user's own id, needed client-side to compare against winner_user_id.

Admin config CRUD refactored to a shared field tuple (_CONFIG_FIELDS)
instead of repeating the same 7-then-8 field list three times.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 16:04:02 +02:00

58 lines
2.0 KiB
Python

from datetime import timedelta, timezone
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.models import RoundParticipant
from app.db.session import get_session
from app.rounds.config import get_round_config
from app.rounds.service import get_active_round
router = APIRouter(prefix="/rounds", tags=["rounds"])
class CurrentRoundResponse(BaseModel):
round_id: int | None = None
status: str | None = None
opened_at: str | None = None
closes_at: str | None = None
participant_count: int = 0
bet_amount_sats: int
jackpot_sats: int = 0
draw_animation_seconds: int
winner_user_id: int | None = None
winner_amount_sats: int | None = None
@router.get("/current", response_model=CurrentRoundResponse)
async def current_round(session: AsyncSession = Depends(get_session)) -> CurrentRoundResponse:
config = await get_round_config(session)
round_ = await get_active_round(session)
if round_ is None:
await session.commit()
return CurrentRoundResponse(
bet_amount_sats=config.bet_amount_sats, draw_animation_seconds=config.draw_animation_seconds
)
participant_count = await session.scalar(
select(func.count()).select_from(RoundParticipant).where(RoundParticipant.round_id == round_.id)
) or 0
opened_at = round_.opened_at.replace(tzinfo=timezone.utc)
closes_at = opened_at + timedelta(seconds=config.round_duration_seconds)
await session.commit()
return CurrentRoundResponse(
round_id=round_.id,
status=round_.status,
opened_at=opened_at.isoformat(),
closes_at=closes_at.isoformat(),
participant_count=participant_count,
bet_amount_sats=config.bet_amount_sats,
jackpot_sats=participant_count * config.bet_amount_sats,
draw_animation_seconds=config.draw_animation_seconds,
winner_user_id=round_.winner_user_id,
winner_amount_sats=round_.winner_amount_sats,
)