151 lines
4.8 KiB
Rust
151 lines
4.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,
|
|
models::pack::PackOpenResult,
|
|
services::{club as club_svc, objective, pack as pack_svc, profile as profile_svc, statistics},
|
|
};
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct BuyPackRequest {
|
|
pub pack_definition_id: String,
|
|
}
|
|
|
|
pub async fn post_buy_pack(
|
|
State(state): State<AppState>,
|
|
game: GameId,
|
|
Json(req): Json<BuyPackRequest>,
|
|
) -> 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 pack = pack_svc::buy_pack(
|
|
&state.pool,
|
|
&state.pack_defs,
|
|
&club.id,
|
|
&req.pack_definition_id,
|
|
)
|
|
.await?;
|
|
Ok(Json(
|
|
json!({ "pack": pack, "message": "Pack purchased successfully" }),
|
|
))
|
|
}
|
|
|
|
/// List all purchasable pack definitions with their coin costs.
|
|
pub async fn get_pack_store(State(state): State<AppState>) -> AppResult<Json<Value>> {
|
|
let store: Vec<Value> = state
|
|
.pack_defs
|
|
.iter()
|
|
.map(|d| {
|
|
let total_cards: u8 = d.slots.iter().map(|s| s.count).sum();
|
|
json!({
|
|
"id": d.id,
|
|
"name": d.name,
|
|
"description": d.description,
|
|
"cost_coins": d.cost_coins,
|
|
"total_cards": total_cards,
|
|
})
|
|
})
|
|
.collect();
|
|
Ok(Json(json!({ "packs": store })))
|
|
}
|
|
|
|
pub async fn get_packs(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 packs = pack_svc::get_unopened_packs(&state.pool, &club.id).await?;
|
|
|
|
let with_defs: Vec<Value> = packs
|
|
.iter()
|
|
.map(|p| {
|
|
let def = state.pack_defs.iter().find(|d| d.id == p.definition_id);
|
|
json!({
|
|
"pack_id": p.id,
|
|
"definition_id": p.definition_id,
|
|
"name": def.map(|d| &d.name),
|
|
"description": def.map(|d| &d.description),
|
|
"created_at": p.created_at,
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
Ok(Json(json!({ "packs": with_defs })))
|
|
}
|
|
|
|
/// Return recently opened packs with the card IDs they contained.
|
|
pub async fn get_pack_history(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 opened = sqlx::query_as::<_, crate::models::pack::Pack>(
|
|
"SELECT id, club_id, definition_id, opened, created_at, opened_cards, opened_at \
|
|
FROM packs WHERE club_id = ? AND opened = 1 ORDER BY opened_at DESC LIMIT 50",
|
|
)
|
|
.bind(&club.id)
|
|
.fetch_all(&state.pool)
|
|
.await?;
|
|
|
|
let history: Vec<Value> = opened
|
|
.iter()
|
|
.map(|p| {
|
|
let def = state.pack_defs.iter().find(|d| d.id == p.definition_id);
|
|
// Expand card_ids into full card definitions
|
|
let cards: Vec<Value> = p
|
|
.opened_cards
|
|
.as_deref()
|
|
.and_then(|s| serde_json::from_str::<Vec<String>>(s).ok())
|
|
.unwrap_or_default()
|
|
.iter()
|
|
.map(|id| {
|
|
json!({
|
|
"card_id": id,
|
|
"card": state.card_db.get(id),
|
|
})
|
|
})
|
|
.collect();
|
|
json!({
|
|
"pack_id": p.id,
|
|
"definition_id": p.definition_id,
|
|
"name": def.map(|d| &d.name),
|
|
"opened_at": p.opened_at,
|
|
"cards": cards,
|
|
})
|
|
})
|
|
.collect();
|
|
|
|
Ok(Json(json!({ "history": history, "total": history.len() })))
|
|
}
|
|
|
|
pub async fn post_open_pack(
|
|
State(state): State<AppState>,
|
|
game: GameId,
|
|
Path(pack_id): Path<String>,
|
|
) -> AppResult<Json<PackOpenResult>> {
|
|
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 = pack_svc::open_pack(
|
|
&state.pool,
|
|
&state.card_db,
|
|
&state.pack_defs,
|
|
&club.id,
|
|
&pack_id,
|
|
)
|
|
.await?;
|
|
|
|
statistics::increment_packs_opened(&state.pool, &profile.id).await?;
|
|
objective::increment_metric(&state.pool, &profile.id, &state.obj_defs, "packsopened", 1)
|
|
.await?;
|
|
let _ = crate::services::achievement::check_and_unlock(
|
|
&state.pool, &state.achievement_defs, &profile.id, &club.id,
|
|
).await;
|
|
|
|
Ok(Json(result))
|
|
}
|