Files
OpenFUT-Core/src/routes/fut_champs.rs
T
2026-08-07 12:03:21 -07:00

127 lines
3.8 KiB
Rust

use crate::extractors::GameId;
use axum::{
extract::{Path, State},
Json,
};
use serde::Deserialize;
use serde_json::{json, Value};
use crate::{
app::AppState,
error::AppResult,
services::{club as club_svc, fut_champs as champs_svc, profile as profile_svc, season as season_svc},
};
/// GET /fut-champs — current active session, or null if none.
pub async fn get_fut_champs(State(state): State<AppState>, game: GameId) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool, game.as_str()).await?;
let session = champs_svc::get_active_session(&state.pool, &profile.id).await?;
Ok(Json(json!({
"session": session,
"max_matches": crate::models::fut_champs::MAX_MATCHES,
})))
}
/// POST /fut-champs/start — open a new FUT Champions week.
pub async fn post_start_fut_champs(State(state): State<AppState>, game: GameId) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool, game.as_str()).await?;
let session = champs_svc::start_session(&state.pool, &profile.id).await?;
Ok(Json(json!({
"session": session,
"message": "FUT Champions week started — play up to 30 matches",
})))
}
#[derive(Deserialize)]
pub struct ChampsMatchRequest {
pub goals_for: i64,
pub goals_against: i64,
}
/// POST /fut-champs/:session_id/result — record a match in this session.
pub async fn post_champs_result(
State(state): State<AppState>,
game: GameId,
Path(session_id): Path<String>,
Json(req): Json<ChampsMatchRequest>,
) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool, game.as_str()).await?;
let session = champs_svc::record_match(
&state.pool,
&profile.id,
&session_id,
req.goals_for,
req.goals_against,
)
.await?;
let outcome = if req.goals_for > req.goals_against {
"win"
} else if req.goals_for == req.goals_against {
"draw"
} else {
"loss"
};
Ok(Json(json!({
"session": session,
"outcome": outcome,
"matches_remaining": session.matches_remaining(),
"auto_completed": session.is_complete(),
})))
}
/// POST /fut-champs/:session_id/claim — claim end-of-week rewards.
pub async fn post_claim_champs_rewards(
State(state): State<AppState>,
game: GameId,
Path(session_id): Path<String>,
) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool, game.as_str()).await?;
let club = club_svc::get_club_by_profile(&state.pool, &profile.id).await?;
let result = champs_svc::claim_rewards(
&state.pool,
&profile.id,
&session_id,
&club.id,
&state.pack_defs,
)
.await?;
Ok(Json(result))
}
/// GET /fut-champs/history — past sessions, newest first.
pub async fn get_champs_history(State(state): State<AppState>, game: GameId) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool, game.as_str()).await?;
let history = champs_svc::get_history(&state.pool, &profile.id).await?;
Ok(Json(json!({
"history": history,
"total": history.len(),
})))
}
/// POST /rivals/claim-weekly — claim weekly Division Rivals reward.
pub async fn post_claim_rivals_reward(State(state): State<AppState>, game: GameId) -> AppResult<Json<Value>> {
let profile = profile_svc::get_active_profile(&state.pool, game.as_str()).await?;
let club = club_svc::get_club_by_profile(&state.pool, &profile.id).await?;
// Ensure a season row exists
season_svc::get_or_create(&state.pool, &profile.id).await?;
let result = champs_svc::claim_rivals_reward(
&state.pool,
&profile.id,
&club.id,
&state.pack_defs,
)
.await?;
Ok(Json(result))
}