feat: expose bracket results and discovery feed
Verify and deploy API / verify-deploy (push) Successful in 1m47s
Verify and deploy API / verify-deploy (push) Successful in 1m47s
This commit is contained in:
@@ -16,6 +16,7 @@ from .schemas import (
|
||||
LinkStartOut,
|
||||
LoginRequest,
|
||||
LoginResponse,
|
||||
PublicRunOut,
|
||||
RunOut,
|
||||
TestCard,
|
||||
TestDetail,
|
||||
@@ -88,7 +89,8 @@ def list_tests(db: Session = Depends(get_db)) -> list[TestCard]:
|
||||
slug=test.slug,
|
||||
title=test.title,
|
||||
subtitle=test.subtitle,
|
||||
emoji=test.emoji,
|
||||
description=test.subtitle,
|
||||
cover_url=f"/assets/test-covers/{test.slug}.jpg",
|
||||
accent=test.accent,
|
||||
candidate_count=len(test.candidates),
|
||||
run_count=counts.get(test.id, 0),
|
||||
@@ -111,12 +113,19 @@ def get_test(slug: str, db: Session = Depends(get_db)) -> TestDetail:
|
||||
slug=test.slug,
|
||||
title=test.title,
|
||||
subtitle=test.subtitle,
|
||||
emoji=test.emoji,
|
||||
description=test.subtitle,
|
||||
cover_url=f"/assets/test-covers/{test.slug}.jpg",
|
||||
accent=test.accent,
|
||||
candidate_count=len(test.candidates),
|
||||
run_count=run_count,
|
||||
candidates=[
|
||||
{"id": c.id, "name": c.name, "emoji": c.emoji, "seed_order": c.seed_order}
|
||||
{
|
||||
"id": c.id,
|
||||
"name": c.name,
|
||||
"description": None,
|
||||
"image_url": None,
|
||||
"seed_order": c.seed_order,
|
||||
}
|
||||
for c in test.candidates
|
||||
],
|
||||
)
|
||||
@@ -132,10 +141,36 @@ def _run_out(run: TestRun) -> RunOut:
|
||||
champion_name=run.champion.name,
|
||||
runner_up_name=run.runner_up.name if run.runner_up else None,
|
||||
ranking_names=[candidate_by_id[item] for item in run.ranking_ids if item in candidate_by_id],
|
||||
decisions=run.decisions,
|
||||
bracket_size=run.bracket_size,
|
||||
candidate_names=candidate_by_id,
|
||||
completed_at=run.completed_at,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/results/discover", response_model=list[PublicRunOut])
|
||||
def discover_results(
|
||||
limit: int = Query(default=30, ge=1, le=100),
|
||||
db: Session = Depends(get_db),
|
||||
) -> list[PublicRunOut]:
|
||||
runs = db.scalars(
|
||||
select(TestRun)
|
||||
.options(selectinload(TestRun.test), selectinload(TestRun.champion))
|
||||
.order_by(TestRun.completed_at.desc())
|
||||
.limit(limit)
|
||||
).all()
|
||||
return [
|
||||
PublicRunOut(
|
||||
id=run.id,
|
||||
test_slug=run.test.slug,
|
||||
test_title=run.test.title,
|
||||
champion_name=run.champion.name,
|
||||
completed_at=run.completed_at,
|
||||
)
|
||||
for run in runs
|
||||
]
|
||||
|
||||
|
||||
@router.post("/tests/{slug}/runs", response_model=RunOut, status_code=201)
|
||||
def complete_run(
|
||||
slug: str,
|
||||
|
||||
@@ -25,7 +25,8 @@ class LoginResponse(BaseModel):
|
||||
class CandidateOut(BaseModel):
|
||||
id: str
|
||||
name: str
|
||||
emoji: str | None
|
||||
description: str | None = None
|
||||
image_url: str | None = None
|
||||
seed_order: int
|
||||
|
||||
|
||||
@@ -33,7 +34,8 @@ class TestCard(BaseModel):
|
||||
slug: str
|
||||
title: str
|
||||
subtitle: str
|
||||
emoji: str
|
||||
description: str
|
||||
cover_url: str
|
||||
accent: str
|
||||
candidate_count: int
|
||||
run_count: int
|
||||
@@ -66,12 +68,23 @@ class RunOut(BaseModel):
|
||||
champion_name: str
|
||||
runner_up_name: str | None
|
||||
ranking_names: list[str]
|
||||
decisions: list[DecisionIn]
|
||||
bracket_size: int
|
||||
candidate_names: dict[str, str]
|
||||
completed_at: datetime
|
||||
share_templates: list[str] = Field(
|
||||
default_factory=lambda: ["celebration", "editorial", "sticker"]
|
||||
)
|
||||
|
||||
|
||||
class PublicRunOut(BaseModel):
|
||||
id: str
|
||||
test_slug: str
|
||||
test_title: str
|
||||
champion_name: str
|
||||
completed_at: datetime
|
||||
|
||||
|
||||
class LinkStartOut(BaseModel):
|
||||
code: str
|
||||
expires_at: datetime
|
||||
|
||||
@@ -57,6 +57,10 @@ def test_login_complete_and_read_result():
|
||||
},
|
||||
)
|
||||
assert created.status_code == 201, created.text
|
||||
assert created.json()["decisions"][0]["winner_id"] == left["id"]
|
||||
assert created.json()["candidate_names"][left["id"]] == "蛋炒饭"
|
||||
public = client.get("/api/v1/results/discover").json()
|
||||
assert public[0]["champion_name"] == "蛋炒饭"
|
||||
history = client.get("/api/v1/me/results?test_slug=rice", headers=headers).json()
|
||||
assert history[0]["champion_name"] == "蛋炒饭"
|
||||
assert client.post("/api/v1/auth/logout", headers=headers).status_code == 204
|
||||
|
||||
Reference in New Issue
Block a user