feat: finishing gacha feature

This commit is contained in:
Maulana Sodiqin
2025-05-21 19:37:30 +07:00
parent 33a2ae86c6
commit 465cbee2c3
10 changed files with 80 additions and 715 deletions
@@ -1,4 +1,5 @@
use crate::{ResourceEnum, make_thing};
use crate::{GachaRollQueryDto, ResourceEnum, make_thing};
use imphnen_iam::get_iso_date;
use serde::{Deserialize, Serialize};
use surrealdb::{Uuid, sql::Thing};
@@ -30,8 +31,8 @@ impl Default for GachaClaimSchema {
&Uuid::new_v4().to_string(),
),
is_deleted: false,
created_at: None,
updated_at: None,
created_at: Some(get_iso_date()),
updated_at: Some(get_iso_date()),
}
}
}
@@ -46,8 +47,20 @@ impl GachaClaimSchema {
user: make_thing(&ResourceEnum::Users.to_string(), &dto.user_id),
item: make_thing(&ResourceEnum::GachaItems.to_string(), &dto.item_id),
is_deleted: false,
created_at: None,
updated_at: None,
created_at: Some(get_iso_date()),
updated_at: Some(get_iso_date()),
}
}
pub fn roll(roll: GachaRollQueryDto, user_id: Thing) -> Self {
Self {
id: make_thing(
&ResourceEnum::GachaClaims.to_string(),
&Uuid::new_v4().to_string(),
),
user: user_id,
item: roll.item.id.clone(),
..Default::default()
}
}
}
@@ -88,7 +88,7 @@ pub async fn post_execute_gacha_roll(
)
.await
{
Ok(_) => GachaRollService::execute_roll_once(&state).await,
Ok(_) => GachaRollService::execute_roll_once(headers, &state).await,
Err(response) => response,
}
}
@@ -8,7 +8,6 @@ use validator::Validate;
pub struct GachaRollRequestDto {
#[validate(length(min = 1, message = "Item ID must not be empty"))]
pub item_id: String,
#[validate(range(min = 1, message = "Weight must be greater than zero"))]
pub weight: f32,
#[validate(range(min = 1, message = "Quantity must be at least 1"))]
pub quantity: i32,
@@ -18,7 +17,7 @@ pub struct GachaRollRequestDto {
pub struct GachaRollItemDto {
pub id: String,
pub item: GachaItemDto,
pub weight: String,
pub weight: f32,
pub quantity: i32,
pub is_deleted: bool,
pub created_at: Option<String>,
@@ -30,7 +29,7 @@ impl GachaRollItemDto {
Self {
id: dto.id.id.to_raw(),
item: GachaItemDto::from(dto.item.clone()),
weight: dto.weight.to_string(),
weight: dto.weight.clone(),
quantity: dto.quantity,
is_deleted: dto.is_deleted,
created_at: dto.created_at.clone(),
@@ -2,6 +2,7 @@ use super::GachaRollQueryDto;
use super::GachaRollSchema;
use crate::{AppState, DetailQueryBuilder, ResourceEnum};
use anyhow::{Result, bail};
use imphnen_iam::ListQueryBuilder;
use rand::prelude::*;
use rand::rng;
use rand_distr::weighted::WeightedIndex;
@@ -50,12 +51,10 @@ impl<'a> GachaRollRepository<'a> {
pub async fn query_all_active_rolls(&self) -> Result<Vec<GachaRollQueryDto>> {
let db = &self.state.surrealdb_ws;
let sql = DetailQueryBuilder::new(ResourceEnum::GachaRolls.to_string())
.with_where("is_deleted")
.where_value("false")
let builder = ListQueryBuilder::new(ResourceEnum::GachaRolls.to_string())
.with_select_fields(vec!["*"])
.with_fetch("item")
.build();
.with_fetch(Some(vec!["item"]));
let sql = builder.build();
let result: Vec<GachaRollQueryDto> = db.query(sql).await?.take(0)?;
Ok(result)
}
@@ -1,10 +1,11 @@
use crate::{
AppState, GachaRollItemDto, GachaRollRepository, GachaRollRequestDto,
GachaRollSchema, ResponseSuccessDto, common_response, success_response,
validate_request,
AppState, GachaClaimRepository, GachaClaimSchema, GachaRollItemDto,
GachaRollRepository, GachaRollRequestDto, GachaRollSchema, ResponseSuccessDto,
common_response, success_response, validate_request,
};
use axum::http::StatusCode;
use axum::http::{HeaderMap, StatusCode};
use axum::response::Response;
use imphnen_iam::{UsersRepository, extract_email};
pub struct GachaRollService;
@@ -34,13 +35,29 @@ impl GachaRollService {
}
}
pub async fn execute_roll_once(state: &AppState) -> Response {
pub async fn execute_roll_once(headers: HeaderMap, state: &AppState) -> Response {
let repo = GachaRollRepository::new(state);
let repo_claim = GachaClaimRepository::new(state);
let repo_user = UsersRepository::new(state);
let Some(email) = extract_email(&headers) else {
return common_response(StatusCode::UNAUTHORIZED, "Unauthorized");
};
let Ok(user) = repo_user.query_user_by_email(email.to_string()).await else {
return common_response(StatusCode::NOT_FOUND, "User not found");
};
match repo.query_all_active_rolls().await {
Ok(rolls) => match GachaRollRepository::roll_once(&rolls) {
Some(roll) => success_response(ResponseSuccessDto {
data: GachaRollItemDto::from(&roll),
}),
Some(roll) => {
let claim = GachaClaimSchema::roll(roll.clone(), user.id);
match repo_claim.query_create_gacha_claim(claim).await {
Ok(_) => success_response(ResponseSuccessDto {
data: GachaRollItemDto::from(&roll),
}),
Err(e) => {
common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string())
}
}
}
None => common_response(StatusCode::NOT_FOUND, "No rollable item available"),
},
Err(e) => common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),