bfd6de6896
CI / Build, lint & test (push) Failing after 1m21s
Draft v2 — stateful FUT-style pick sessions:
- POST /draft/start?difficulty=<> — creates session, returns 5
candidates for GK slot (position order: GK RB CB CB LB CDM CM CAM RW ST LW)
- POST /draft/sessions/:id/pick { card_id } — validates candidate,
advances to next position; on last pick grants coins+pack reward
(avg OVR ≥84 → gold pack + 2000 coins, ≥78 → silver + 1000, else 400)
- GET /draft/sessions/:id — session state with per-pick cards
- POST /draft/sessions/:id/abandon — cancel without reward
- Migration 0005_draft_sessions.sql
Quick-sell:
- DELETE /collection/:owned_card_id — removes card, credits coins based
on overall (85+ → 1500, 80-84 → 900, 75-79 → 600, 65-74 → 300, <65 → 150)
Objectives:
- GET /objectives/:id — single objective with progress
- POST /objectives/:id/claim — claim reward by URL param (complement to
existing POST /objectives/claim body-param endpoint)
Market:
- GET /market/my-listings — active listings posted by current club
- DELETE /market/listings/:id — cancel a listing, returns card to collection
Tests: 9 new integration tests (37 total, all passing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
73 lines
2.2 KiB
Rust
73 lines
2.2 KiB
Rust
use axum::{
|
|
extract::{Path, State},
|
|
Json,
|
|
};
|
|
use serde::Deserialize;
|
|
use serde_json::{json, Value};
|
|
|
|
use crate::{
|
|
app::AppState,
|
|
error::{AppError, AppResult},
|
|
services::{club as club_svc, objective as obj_svc, profile as profile_svc},
|
|
};
|
|
|
|
pub async fn get_objectives(State(state): State<AppState>) -> AppResult<Json<Value>> {
|
|
let profile = profile_svc::get_active_profile(&state.pool).await?;
|
|
let objectives =
|
|
obj_svc::get_objectives_with_progress(&state.pool, &profile.id, &state.obj_defs).await?;
|
|
Ok(Json(json!({ "objectives": objectives })))
|
|
}
|
|
|
|
pub async fn get_objective(
|
|
State(state): State<AppState>,
|
|
Path(objective_id): Path<String>,
|
|
) -> AppResult<Json<Value>> {
|
|
let profile = profile_svc::get_active_profile(&state.pool).await?;
|
|
let all =
|
|
obj_svc::get_objectives_with_progress(&state.pool, &profile.id, &state.obj_defs).await?;
|
|
let obj = all
|
|
.into_iter()
|
|
.find(|o| o.definition.id == objective_id)
|
|
.ok_or_else(|| AppError::NotFound(format!("objective '{objective_id}' not found")))?;
|
|
Ok(Json(json!({ "objective": obj })))
|
|
}
|
|
|
|
pub async fn post_claim_objective_by_id(
|
|
State(state): State<AppState>,
|
|
Path(objective_id): Path<String>,
|
|
) -> AppResult<Json<Value>> {
|
|
let profile = profile_svc::get_active_profile(&state.pool).await?;
|
|
let club = club_svc::get_club_by_profile(&state.pool, &profile.id).await?;
|
|
let reward = obj_svc::claim_objective(
|
|
&state.pool,
|
|
&profile.id,
|
|
&club.id,
|
|
&state.obj_defs,
|
|
&objective_id,
|
|
)
|
|
.await?;
|
|
Ok(Json(json!({ "claimed": true, "reward": reward })))
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct ClaimRequest {
|
|
pub objective_id: String,
|
|
}
|
|
|
|
pub async fn post_claim_objective(
|
|
State(state): State<AppState>,
|
|
Json(req): Json<ClaimRequest>,
|
|
) -> AppResult<Json<Value>> {
|
|
let profile = profile_svc::get_active_profile(&state.pool).await?;
|
|
let club = club_svc::get_club_by_profile(&state.pool, &profile.id).await?;
|
|
let reward = obj_svc::claim_objective(
|
|
&state.pool,
|
|
&profile.id,
|
|
&club.id,
|
|
&state.obj_defs,
|
|
&req.objective_id,
|
|
)
|
|
.await?;
|
|
Ok(Json(json!({ "claimed": true, "reward": reward })))
|
|
}
|