Add invite links

This commit is contained in:
2025-12-14 20:39:26 +07:00
parent d0b8eca600
commit 5db2f9c48d
11 changed files with 290 additions and 12 deletions

View File

@@ -18,6 +18,7 @@ from app.schemas import (
MarathonUpdate,
MarathonResponse,
MarathonListItem,
MarathonPublicInfo,
JoinMarathon,
ParticipantInfo,
ParticipantWithUser,
@@ -30,6 +31,35 @@ from app.schemas import (
router = APIRouter(prefix="/marathons", tags=["marathons"])
# Public endpoint (no auth required)
@router.get("/by-code/{invite_code}", response_model=MarathonPublicInfo)
async def get_marathon_by_code(invite_code: str, db: DbSession):
"""Get public marathon info by invite code. No authentication required."""
result = await db.execute(
select(Marathon, func.count(Participant.id).label("participants_count"))
.outerjoin(Participant)
.options(selectinload(Marathon.creator))
.where(Marathon.invite_code == invite_code)
.group_by(Marathon.id)
)
row = result.first()
if not row:
raise HTTPException(status_code=404, detail="Marathon not found")
marathon = row[0]
participants_count = row[1]
return MarathonPublicInfo(
id=marathon.id,
title=marathon.title,
description=marathon.description,
status=marathon.status,
participants_count=participants_count,
creator_nickname=marathon.creator.nickname,
)
def generate_invite_code() -> str:
return secrets.token_urlsafe(8)

View File

@@ -12,6 +12,7 @@ from app.schemas.marathon import (
MarathonUpdate,
MarathonResponse,
MarathonListItem,
MarathonPublicInfo,
ParticipantInfo,
ParticipantWithUser,
JoinMarathon,
@@ -65,6 +66,7 @@ __all__ = [
"MarathonUpdate",
"MarathonResponse",
"MarathonListItem",
"MarathonPublicInfo",
"ParticipantInfo",
"ParticipantWithUser",
"JoinMarathon",

View File

@@ -79,6 +79,19 @@ class JoinMarathon(BaseModel):
invite_code: str
class MarathonPublicInfo(BaseModel):
"""Public info about marathon for invite page (no auth required)"""
id: int
title: str
description: str | None
status: str
participants_count: int
creator_nickname: str
class Config:
from_attributes = True
class LeaderboardEntry(BaseModel):
rank: int
user: UserPublic