1ef2c436ab
CI / Build, lint & test (push) Successful in 2m5s
Adds a data-driven event system (#47 schema, #48 activation, #49 TOTW): - EventDefinition JSON schema (event_type, effects, date range, is_manual) - data/events/totw_week1.json — TOTW event active by date range (2024–2030), injects 5 TOTW cards into the market as [EVENT] listings - data/events/seasonal_events.json — Spring Festival and Icon Weekend, manual-activation-only example events - migrations/0004_events.sql — events override table (NULL/1/0 per event) - services/event — load_event_definitions, compute_is_active (date range + manual override), get_active_events, get_all_with_status, activate/deactivate - routes/events — GET /events, GET /events/:id, POST .../activate, .../deactivate - services/market::refresh_npc_listings now accepts event_defs, injects bonus market cards from active events at 2× premium price - 5 new integration tests (events list, single, activate/deactivate cycle, 404 on unknown, market injection verification); 19/19 passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
76 lines
2.3 KiB
Rust
76 lines
2.3 KiB
Rust
use axum::{
|
|
extract::{Query, State},
|
|
Json,
|
|
};
|
|
use serde::Deserialize;
|
|
use serde_json::{json, Value};
|
|
|
|
use crate::{
|
|
app::AppState,
|
|
error::AppResult,
|
|
models::market::{BuyListingRequest, SellCardRequest},
|
|
services::{club as club_svc, market as market_svc, profile as profile_svc},
|
|
};
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct MarketQuery {
|
|
pub min_overall: Option<u8>,
|
|
pub position: Option<String>,
|
|
}
|
|
|
|
pub async fn get_market(
|
|
State(state): State<AppState>,
|
|
Query(query): Query<MarketQuery>,
|
|
) -> AppResult<Json<Value>> {
|
|
let all = market_svc::get_active_listings(&state.pool, &state.card_db).await?;
|
|
let listings: Vec<_> = all
|
|
.into_iter()
|
|
.filter(|l| {
|
|
query
|
|
.min_overall
|
|
.map(|min| l.card.overall >= min)
|
|
.unwrap_or(true)
|
|
&& query
|
|
.position
|
|
.as_ref()
|
|
.map(|p| l.card.position.eq_ignore_ascii_case(p))
|
|
.unwrap_or(true)
|
|
})
|
|
.collect();
|
|
Ok(Json(
|
|
json!({ "listings": listings, "total": listings.len() }),
|
|
))
|
|
}
|
|
|
|
pub async fn post_market_buy(
|
|
State(state): State<AppState>,
|
|
Json(req): Json<BuyListingRequest>,
|
|
) -> 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 card = market_svc::buy_listing(&state.pool, &state.card_db, &club.id, &req).await?;
|
|
Ok(Json(
|
|
json!({ "purchased_card": card, "message": "Card purchased successfully" }),
|
|
))
|
|
}
|
|
|
|
pub async fn post_market_sell(
|
|
State(state): State<AppState>,
|
|
Json(req): Json<SellCardRequest>,
|
|
) -> 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 new_balance = market_svc::sell_card(&state.pool, &club.id, &req).await?;
|
|
Ok(Json(
|
|
json!({ "new_coin_balance": new_balance, "message": "Card sold to NPC market" }),
|
|
))
|
|
}
|
|
|
|
pub async fn post_market_refresh(State(state): State<AppState>) -> AppResult<Json<Value>> {
|
|
let count =
|
|
market_svc::refresh_npc_listings(&state.pool, &state.card_db, &state.event_defs).await?;
|
|
Ok(Json(json!({ "listings_generated": count })))
|
|
}
|