326 lines
7.4 KiB
Rust
326 lines
7.4 KiB
Rust
use chrono::{DateTime, Utc};
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::{FromRow, Type};
|
|
use uuid::Uuid;
|
|
use validator::Validate;
|
|
|
|
/// Card rarity enum matching Python implementation
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Type)]
|
|
#[sqlx(type_name = "card_rarity", rename_all = "lowercase")]
|
|
pub enum CardRarity {
|
|
#[serde(rename = "normal")]
|
|
Normal,
|
|
#[serde(rename = "rare")]
|
|
Rare,
|
|
#[serde(rename = "super_rare")]
|
|
SuperRare,
|
|
#[serde(rename = "kira")]
|
|
Kira,
|
|
#[serde(rename = "unique")]
|
|
Unique,
|
|
}
|
|
|
|
impl CardRarity {
|
|
pub fn multiplier(&self) -> f64 {
|
|
match self {
|
|
CardRarity::Normal => 1.0,
|
|
CardRarity::Rare => 1.5,
|
|
CardRarity::SuperRare => 2.0,
|
|
CardRarity::Kira => 3.0,
|
|
CardRarity::Unique => 5.0,
|
|
}
|
|
}
|
|
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
CardRarity::Normal => "normal",
|
|
CardRarity::Rare => "rare",
|
|
CardRarity::SuperRare => "super_rare",
|
|
CardRarity::Kira => "kira",
|
|
CardRarity::Unique => "unique",
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Database Models
|
|
|
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
|
pub struct User {
|
|
pub id: i32,
|
|
pub did: String,
|
|
pub handle: String,
|
|
pub created_at: DateTime<Utc>,
|
|
pub updated_at: DateTime<Utc>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
|
pub struct CardMaster {
|
|
pub id: i32,
|
|
pub name: String,
|
|
pub base_cp_min: i32,
|
|
pub base_cp_max: i32,
|
|
pub color: String,
|
|
pub description: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
|
pub struct UserCard {
|
|
pub id: i32,
|
|
pub user_did: String,
|
|
pub card_id: i32,
|
|
pub cp: i32,
|
|
pub status: CardRarity,
|
|
pub skill: Option<String>,
|
|
pub obtained_at: DateTime<Utc>,
|
|
pub is_unique: bool,
|
|
pub unique_id: Option<Uuid>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
|
pub struct UniqueCardRegistry {
|
|
pub id: i32,
|
|
pub unique_id: Uuid,
|
|
pub card_id: i32,
|
|
pub owner_did: String,
|
|
pub obtained_at: DateTime<Utc>,
|
|
pub verse_skill_id: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
|
pub struct DrawHistory {
|
|
pub id: i32,
|
|
pub user_did: String,
|
|
pub card_id: i32,
|
|
pub status: CardRarity,
|
|
pub cp: i32,
|
|
pub is_paid: bool,
|
|
pub drawn_at: DateTime<Utc>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
|
|
pub struct GachaPool {
|
|
pub id: i32,
|
|
pub name: String,
|
|
pub description: String,
|
|
pub is_active: bool,
|
|
pub start_at: Option<DateTime<Utc>>,
|
|
pub end_at: Option<DateTime<Utc>>,
|
|
pub pickup_card_ids: Vec<i32>,
|
|
pub rate_up_multiplier: f64,
|
|
}
|
|
|
|
/// API Request/Response Models
|
|
|
|
#[derive(Debug, Deserialize, Validate)]
|
|
pub struct LoginRequest {
|
|
#[validate(length(min = 1))]
|
|
pub identifier: String,
|
|
#[validate(length(min = 1))]
|
|
pub password: String,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct LoginResponse {
|
|
pub access_token: String,
|
|
pub token_type: String,
|
|
pub expires_in: u64,
|
|
pub user: UserInfo,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct UserInfo {
|
|
pub did: String,
|
|
pub handle: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Validate)]
|
|
pub struct CardDrawRequest {
|
|
pub user_did: String,
|
|
#[serde(default)]
|
|
pub is_paid: bool,
|
|
pub pool_id: Option<i32>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct CardDrawResponse {
|
|
pub card: UserCardResponse,
|
|
pub master: CardMasterResponse,
|
|
pub is_unique: bool,
|
|
pub animation_type: String,
|
|
pub draw_history_id: i32,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct UserCardResponse {
|
|
pub id: i32,
|
|
pub card_id: i32,
|
|
pub cp: i32,
|
|
pub status: CardRarity,
|
|
pub skill: Option<String>,
|
|
pub obtained_at: DateTime<Utc>,
|
|
pub is_unique: bool,
|
|
pub unique_id: Option<Uuid>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct CardMasterResponse {
|
|
pub id: i32,
|
|
pub name: String,
|
|
pub base_cp_min: i32,
|
|
pub base_cp_max: i32,
|
|
pub color: String,
|
|
pub description: String,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct UserCardCollectionResponse {
|
|
pub user_did: String,
|
|
pub cards: Vec<UserCardWithMaster>,
|
|
pub total_count: i32,
|
|
pub unique_count: i32,
|
|
pub rarity_breakdown: RarityBreakdown,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct UserCardWithMaster {
|
|
pub card: UserCardResponse,
|
|
pub master: CardMasterResponse,
|
|
}
|
|
|
|
/// Database query result for JOIN operations
|
|
#[derive(Debug, Clone, FromRow)]
|
|
pub struct UserCardWithMasterQuery {
|
|
// user_cards fields
|
|
pub id: i32,
|
|
pub user_did: String,
|
|
pub card_id: i32,
|
|
pub cp: i32,
|
|
pub status: String,
|
|
pub obtained_at: DateTime<Utc>,
|
|
pub is_unique: bool,
|
|
pub unique_id: Option<Uuid>,
|
|
// card_master fields
|
|
pub master_id: i32,
|
|
pub name: String,
|
|
pub base_cp_min: i32,
|
|
pub base_cp_max: i32,
|
|
pub color: String,
|
|
pub description: String,
|
|
}
|
|
|
|
/// Database query result for unique card registry
|
|
#[derive(Debug, Clone, FromRow)]
|
|
pub struct UniqueCardQuery {
|
|
pub card_id: i32,
|
|
pub card_name: String,
|
|
pub owner_did: Option<String>,
|
|
pub owner_handle: Option<String>,
|
|
pub obtained_at: Option<DateTime<Utc>>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct RarityBreakdown {
|
|
pub normal: i32,
|
|
pub rare: i32,
|
|
pub super_rare: i32,
|
|
pub kira: i32,
|
|
pub unique: i32,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct UniqueCardRegistryResponse {
|
|
pub unique_cards: Vec<UniqueCardInfo>,
|
|
pub total_unique_cards: i32,
|
|
pub available_unique_cards: i32,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct UniqueCardInfo {
|
|
pub card_id: i32,
|
|
pub card_name: String,
|
|
pub owner_did: Option<String>,
|
|
pub owner_handle: Option<String>,
|
|
pub obtained_at: Option<DateTime<Utc>>,
|
|
pub is_available: bool,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct GachaStatsResponse {
|
|
pub probabilities: GachaProbabilities,
|
|
pub total_draws: i32,
|
|
pub total_unique_cards: i32,
|
|
pub available_unique_cards: i32,
|
|
pub rarity_distribution: RarityBreakdown,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct GachaProbabilities {
|
|
pub normal: f64,
|
|
pub rare: f64,
|
|
pub super_rare: f64,
|
|
pub kira: f64,
|
|
pub unique: f64,
|
|
pub paid_multiplier: f64,
|
|
}
|
|
|
|
/// External Data Models (from ai.json)
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct ExternalCardData {
|
|
pub ai: AiData,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct AiData {
|
|
pub card: CardData,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct CardData {
|
|
pub cards: Vec<ExternalCard>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct ExternalCard {
|
|
pub id: i32,
|
|
pub name: String,
|
|
pub cp: CpRange,
|
|
pub color: String,
|
|
pub skill: String,
|
|
pub lang: Option<LangData>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct CpRange {
|
|
pub min: i32,
|
|
pub max: i32,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct LangData {
|
|
pub ja: Option<JapaneseData>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct JapaneseData {
|
|
pub name: Option<String>,
|
|
pub skill: Option<String>,
|
|
}
|
|
|
|
/// atproto Models
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct AtprotoCardRecord {
|
|
#[serde(rename = "$type")]
|
|
pub record_type: String,
|
|
#[serde(rename = "cardId")]
|
|
pub card_id: i32,
|
|
pub cp: i32,
|
|
pub status: String,
|
|
#[serde(rename = "obtainedAt")]
|
|
pub obtained_at: DateTime<Utc>,
|
|
#[serde(rename = "isUnique")]
|
|
pub is_unique: bool,
|
|
#[serde(rename = "uniqueId")]
|
|
pub unique_id: Option<Uuid>,
|
|
} |