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>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
use axum::{
|
||||
extract::{Path, State},
|
||||
Json,
|
||||
};
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::{
|
||||
app::AppState,
|
||||
error::{AppError, AppResult},
|
||||
services::event as event_svc,
|
||||
};
|
||||
|
||||
pub async fn get_events(State(state): State<AppState>) -> AppResult<Json<Value>> {
|
||||
let events = event_svc::get_all_with_status(&state.pool, &state.event_defs).await?;
|
||||
let active_count = events.iter().filter(|e| e.is_active).count();
|
||||
Ok(Json(json!({
|
||||
"events": events,
|
||||
"total": events.len(),
|
||||
"active_count": active_count,
|
||||
})))
|
||||
}
|
||||
|
||||
pub async fn get_event(
|
||||
State(state): State<AppState>,
|
||||
Path(event_id): Path<String>,
|
||||
) -> AppResult<Json<Value>> {
|
||||
let def = state
|
||||
.event_defs
|
||||
.iter()
|
||||
.find(|d| d.id == event_id)
|
||||
.ok_or_else(|| AppError::NotFound(format!("event '{event_id}' not found")))?;
|
||||
|
||||
let is_active = event_svc::is_event_active(&state.pool, def).await?;
|
||||
Ok(Json(json!({
|
||||
"event": def,
|
||||
"is_active": is_active,
|
||||
})))
|
||||
}
|
||||
|
||||
pub async fn post_activate_event(
|
||||
State(state): State<AppState>,
|
||||
Path(event_id): Path<String>,
|
||||
) -> AppResult<Json<Value>> {
|
||||
event_svc::activate_event(&state.pool, &event_id, &state.event_defs).await?;
|
||||
Ok(Json(json!({ "activated": event_id, "is_active": true })))
|
||||
}
|
||||
|
||||
pub async fn post_deactivate_event(
|
||||
State(state): State<AppState>,
|
||||
Path(event_id): Path<String>,
|
||||
) -> AppResult<Json<Value>> {
|
||||
event_svc::deactivate_event(&state.pool, &event_id, &state.event_defs).await?;
|
||||
Ok(Json(json!({ "deactivated": event_id, "is_active": false })))
|
||||
}
|
||||
@@ -69,6 +69,7 @@ pub async fn post_market_sell(
|
||||
}
|
||||
|
||||
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).await?;
|
||||
let count =
|
||||
market_svc::refresh_npc_listings(&state.pool, &state.card_db, &state.event_defs).await?;
|
||||
Ok(Json(json!({ "listings_generated": count })))
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ pub mod auth;
|
||||
pub mod cards;
|
||||
pub mod club;
|
||||
pub mod draft;
|
||||
pub mod events;
|
||||
pub mod health;
|
||||
pub mod market;
|
||||
pub mod matches;
|
||||
|
||||
Reference in New Issue
Block a user