feat(club): persist active home/away kit assignments
CI / Build, lint & test (push) Successful in 2m50s
CI / Build, lint & test (push) Successful in 2m50s
Kits are ownership-backed club items: the owned instance stays in the generic owned_cards inventory and only the two active roles get their own table. This mirrors the squad_managers precedent and keeps every FIFA-specific resourceId/wire concern in the game adapter. * migration 0024: club_kit_assignments(club_id, slot, owned_card_id) with a UNIQUE owned_card_id (one instance cannot hold both roles) and ON DELETE CASCADE from owned_cards so a quick-sell clears the role. * a BEFORE UPDATE OF club_id trigger clears the designation on a market transfer, which moves ownership by UPDATE and so is not covered by the cascade. * set_active_club_kits replaces BOTH slots in one transaction, rejects home == away, and validates each instance against current club ownership, so a half-applied or dangling designation is not representable. * get_active_club_kits revalidates ownership on read, so a stale row can never surface another club's item. * GET/PUT /club/kits expose the pair. Tests cover restart persistence, replace/clear without duplicates, atomic rejection of invalid references, and clearing via delete and transfer.
This commit is contained in:
@@ -163,3 +163,40 @@ pub async fn put_squad_manager(
|
||||
let manager = club_svc::get_squad_manager(&state.pool, &club.id).await?;
|
||||
Ok(Json(json!({ "manager": manager })))
|
||||
}
|
||||
|
||||
/// Return the club's ownership-backed active home/away kit assignments.
|
||||
pub async fn get_active_kits(
|
||||
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?;
|
||||
let kits = club_svc::get_active_club_kits(&state.pool, &club.id).await?;
|
||||
Ok(Json(json!({ "home": kits.home, "away": kits.away })))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetActiveKitsRequest {
|
||||
pub home_owned_card_id: Option<String>,
|
||||
pub away_owned_card_id: Option<String>,
|
||||
}
|
||||
|
||||
/// Atomically replace both active kit assignments. Core enforces ownership and
|
||||
/// distinct instances; game adapters enforce their own definition taxonomy.
|
||||
pub async fn put_active_kits(
|
||||
State(state): State<AppState>,
|
||||
game: GameId,
|
||||
Json(req): Json<SetActiveKitsRequest>,
|
||||
) -> 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?;
|
||||
club_svc::set_active_club_kits(
|
||||
&state.pool,
|
||||
&club.id,
|
||||
req.home_owned_card_id.as_deref(),
|
||||
req.away_owned_card_id.as_deref(),
|
||||
)
|
||||
.await?;
|
||||
let kits = club_svc::get_active_club_kits(&state.pool, &club.id).await?;
|
||||
Ok(Json(json!({ "home": kits.home, "away": kits.away })))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user