Initial commit: OpenFUT Core
Offline Ultimate Team backend — game-independent REST API. - 19 API endpoints: auth, profiles, clubs, cards, packs, squads, objectives, SBCs, match rewards, NPC market, statistics - Axum + SQLite + SQLx with full migrations - Weighted pack generator, SBC validation engine - JSON-driven mod data (cards, packs, objectives, SBCs) - 5 integration tests passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
use crate::{
|
||||
db::Pool,
|
||||
error::{AppError, AppResult},
|
||||
models::club::Club,
|
||||
};
|
||||
use chrono::Utc;
|
||||
|
||||
pub async fn get_club_by_profile(pool: &Pool, profile_id: &str) -> AppResult<Club> {
|
||||
sqlx::query_as::<_, Club>(
|
||||
"SELECT id, profile_id, name, coins, level, created_at, updated_at FROM clubs WHERE profile_id = ? LIMIT 1"
|
||||
)
|
||||
.bind(profile_id)
|
||||
.fetch_optional(pool)
|
||||
.await?
|
||||
.ok_or_else(|| AppError::NotFound("club not found".into()))
|
||||
}
|
||||
|
||||
pub async fn create_club(pool: &Pool, club: &Club) -> AppResult<()> {
|
||||
sqlx::query(
|
||||
"INSERT INTO clubs (id, profile_id, name, coins, level, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)"
|
||||
)
|
||||
.bind(&club.id)
|
||||
.bind(&club.profile_id)
|
||||
.bind(&club.name)
|
||||
.bind(club.coins)
|
||||
.bind(club.level)
|
||||
.bind(club.created_at)
|
||||
.bind(club.updated_at)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn add_coins(pool: &Pool, club_id: &str, amount: i64) -> AppResult<i64> {
|
||||
let now = Utc::now();
|
||||
sqlx::query("UPDATE clubs SET coins = coins + ?, updated_at = ? WHERE id = ?")
|
||||
.bind(amount)
|
||||
.bind(now)
|
||||
.bind(club_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
let new_balance = sqlx::query_scalar::<_, i64>("SELECT coins FROM clubs WHERE id = ?")
|
||||
.bind(club_id)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
Ok(new_balance)
|
||||
}
|
||||
|
||||
pub async fn spend_coins(pool: &Pool, club_id: &str, amount: i64) -> AppResult<i64> {
|
||||
let balance = sqlx::query_scalar::<_, i64>("SELECT coins FROM clubs WHERE id = ?")
|
||||
.bind(club_id)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
if balance < amount {
|
||||
return Err(AppError::BadRequest(format!(
|
||||
"insufficient coins: have {balance}, need {amount}"
|
||||
)));
|
||||
}
|
||||
|
||||
let now = Utc::now();
|
||||
sqlx::query("UPDATE clubs SET coins = coins - ?, updated_at = ? WHERE id = ?")
|
||||
.bind(amount)
|
||||
.bind(now)
|
||||
.bind(club_id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(balance - amount)
|
||||
}
|
||||
Reference in New Issue
Block a user