Compare commits

...

2 commits

Author SHA1 Message Date
Ninjdai
b817d36816 feat: book return and bal stats
Some checks are pending
/ test (push) Waiting to run
2025-08-15 13:14:11 +02:00
Ninjdai
910b10de35 feat: update dependencies 2025-08-14 17:54:51 +02:00
9 changed files with 265 additions and 72 deletions

View file

@ -12,11 +12,10 @@ jobs:
path: |
target/debug
~/.cargo/registry
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/libalexandria.rlib') }}
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
${{ runner.os }}-${{ env.cache-name }}-
- name: Install rust toolchain
uses: https://github.com/dtolnay/rust-toolchain@stable
- run: JWT_SECRET="$(./scripts/generate_secret.sh)" cargo test --verbose

121
Cargo.lock generated
View file

@ -187,7 +187,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -198,7 +198,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -311,7 +311,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -420,7 +420,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -499,9 +499,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.43"
version = "4.5.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f"
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
dependencies = [
"clap_builder",
"clap_derive",
@ -509,9 +509,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.43"
version = "4.5.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65"
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
dependencies = [
"anstream",
"anstyle",
@ -521,14 +521,14 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.41"
version = "4.5.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491"
checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -692,7 +692,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -715,7 +715,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -921,7 +921,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -1419,7 +1419,7 @@ checksum = "6c38228f24186d9cc68c729accb4d413be9eaed6ad07ff79e0270d9e56f3de13"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -1525,9 +1525,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.174"
version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libm"
@ -1535,6 +1535,17 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]]
name = "libredox"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
dependencies = [
"bitflags 2.9.1",
"libc",
"redox_syscall",
]
[[package]]
name = "libsqlite3-sys"
version = "0.30.1"
@ -1792,7 +1803,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -1853,7 +1864,7 @@ dependencies = [
"proc-macro2",
"proc-macro2-diagnostics",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -2037,14 +2048,14 @@ dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
name = "proc-macro2"
version = "1.0.95"
version = "1.0.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
checksum = "d61789d7719defeb74ea5fe81f2fdfdbd28a803847077cecce2ff14e1472f6f1"
dependencies = [
"unicode-ident",
]
@ -2057,7 +2068,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
"version_check",
"yansi",
]
@ -2276,9 +2287,9 @@ dependencies = [
[[package]]
name = "reqwest"
version = "0.12.22"
version = "0.12.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb"
dependencies = [
"base64",
"bytes",
@ -2403,7 +2414,7 @@ dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn 2.0.104",
"syn 2.0.105",
"walkdir",
]
@ -2539,7 +2550,7 @@ dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -2581,7 +2592,7 @@ dependencies = [
"proc-macro2",
"quote",
"sea-bae",
"syn 2.0.104",
"syn 2.0.105",
"unicode-ident",
]
@ -2663,7 +2674,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -2909,7 +2920,7 @@ dependencies = [
"quote",
"sqlx-core",
"sqlx-macros-core",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -2932,7 +2943,7 @@ dependencies = [
"sqlx-mysql",
"sqlx-postgres",
"sqlx-sqlite",
"syn 2.0.104",
"syn 2.0.105",
"tokio",
"url",
]
@ -3108,9 +3119,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.104"
version = "2.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
dependencies = [
"proc-macro2",
"quote",
@ -3134,7 +3145,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -3188,22 +3199,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "2.0.12"
version = "2.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.12"
version = "2.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -3299,7 +3310,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -3441,7 +3452,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -3595,7 +3606,7 @@ checksum = "6d79d08d92ab8af4c5e8a6da20c47ae3f61a0f1dabc1997cdf2d082b757ca08b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -3619,9 +3630,9 @@ dependencies = [
[[package]]
name = "uuid"
version = "1.17.0"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be"
dependencies = [
"js-sys",
"serde",
@ -3702,7 +3713,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
"wasm-bindgen-shared",
]
@ -3737,7 +3748,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3782,11 +3793,11 @@ dependencies = [
[[package]]
name = "whoami"
version = "1.6.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7"
checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d"
dependencies = [
"redox_syscall",
"libredox",
"wasite",
]
@ -3842,7 +3853,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -3853,7 +3864,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -4172,7 +4183,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
"synstructure",
]
@ -4193,7 +4204,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]
@ -4213,7 +4224,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
"synstructure",
]
@ -4253,7 +4264,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.104",
"syn 2.0.105",
]
[[package]]

View file

@ -12,8 +12,8 @@ strip = true # Strip symbols from binary*
[dependencies]
axum = { version = "0.8.4", features = [ "macros", "ws", "tokio" ] }
axum-extra = { version = "0.10.1", features = ["typed-header"] }
reqwest = { version = "0.12.22", features = ["json"] }
sea-orm = { version = "1.1.13", features = [ "sqlx-sqlite", "runtime-tokio-native-tls", "macros" ] }
reqwest = { version = "0.12.23", features = ["json"] }
sea-orm = { version = "1.1.14", features = [ "sqlx-sqlite", "runtime-tokio-native-tls", "macros" ] }
serde = "1.0.219"
serde_json = "1.0.140"
tokio = { version = "1.47.1", features = [ "full" ] }
@ -24,7 +24,7 @@ futures-util = "0.3.31"
log = "0.4.27"
pretty_env_logger = "0.5.0"
argon2 = { version = "0.5.3", features = ["password-hash", "alloc", "rand"] }
clap = { version = "4.5.42", features = ["derive"] }
clap = { version = "4.5.45", features = ["derive"] }
inquire = "0.7.5"
rand_core = { version = "0.9.3", features = ["os_rng"] }
password-hash = { version = "0.5.0", features = ["getrandom"] }

View file

@ -34,6 +34,8 @@ where C: ConnectionTrait {
pub enum Relation {
#[sea_orm(has_many = "super::book_instance::Entity")]
BookInstance,
#[sea_orm(has_one = "super::bal_stats::Entity")]
BalStats,
}
impl Related<super::book_instance::Entity> for Entity {

38
src/entities/bal_stats.rs Normal file
View file

@ -0,0 +1,38 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize, utoipa::ToSchema)]
#[sea_orm(table_name = "BALStats")]
#[schema(title="BalStats", as=entities::BALStats)]
pub struct Model {
#[sea_orm(primary_key, auto_increment = true)]
#[serde(skip_serializing)]
id: u32,
pub bal_id: u32,
pub total_owned_sold_books: u32,
pub total_sold_books: u32,
pub total_owned_collected_money: f32,
pub total_collected_money: f32,
pub total_different_owners: u32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
belongs_to = "super::bal::Entity",
from = "Column::BalId",
to = "super::bal::Column::Id"
)]
Bal,
}
impl Related<super::bal::Entity> for Entity {
fn to() -> RelationDef {
Relation::Bal.def()
}
}
impl ActiveModelBehavior for ActiveModel {}

View file

@ -1,6 +1,7 @@
pub mod prelude;
pub mod bal;
pub mod bal_stats;
pub mod book;
pub mod book_instance;
pub mod owner;

View file

@ -1,5 +1,6 @@
pub use super::bal::Entity as Bal;
pub use super::bal_stats::Entity as BalStats;
pub use super::book::Entity as Book;
pub use super::book_instance::Entity as BookInstance;
pub use super::owner::Entity as Owner;

View file

@ -175,6 +175,8 @@ pub async fn run_server(db: Arc<DatabaseConnection>, port: u16, serve_docs: bool
.routes(routes!(routes::bal::stop_bal))
.routes(routes!(routes::bal::get_bals))
.routes(routes!(routes::bal::get_bal_accounting))
.routes(routes!(routes::bal::return_to_owner))
.routes(routes!(routes::bal::get_stats_by_bal_id))
// Authentication
.route_layer(middleware::from_fn_with_state(shared_state.clone(), routes::auth::auth_middleware))
.routes(routes!(routes::auth::auth))

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, sync::Arc};
use std::{collections::{HashMap, HashSet}, sync::Arc};
use axum::{extract::{Path, State}, Json};
use reqwest::{StatusCode};
@ -6,7 +6,7 @@ use sea_orm::{ActiveModelTrait, ActiveValue::{NotSet, Set}, ColumnTrait, EntityT
use serde::{Deserialize, Serialize};
use utoipa::IntoParams;
use crate::{entities::{bal::{self, BalState}, book_instance, owner, prelude::*}, routes::auth::Claims, AppState};
use crate::{entities::{bal::{self, BalState}, bal_stats, book_instance, owner, prelude::*}, routes::auth::Claims, AppState};
#[derive(IntoParams)]
@ -242,16 +242,49 @@ pub async fn stop_bal(
let mut bal: bal::ActiveModel = bal.into();
bal.state = Set(BalState::Ended);
match bal.update(state.db_conn.as_ref()).await {
Err(e) => {
log::error!(target: "api", "Error while updating bal from api: {:#?}", e);
(StatusCode::INTERNAL_SERVER_ERROR, Json(None))
},
Ok(res) => {
let model = res.try_into_model().expect("All fields should be set once the bal is saved");
(StatusCode::OK, Json(Some(model)))
let model = bal.update(state.db_conn.as_ref()).await.unwrap().try_into_model().expect("All fields should be set once the bal is saved");
let self_owner = Owner::find()
.filter(owner::Column::User.eq(true))
.filter(owner::Column::UserId.eq(claims.user_id))
.one(state.db_conn.as_ref()).await.unwrap().unwrap();
let mut total_sold_books = 0;
let mut total_owned_sold_books = 0;
let mut total_collected_money = 0.;
let mut total_owned_collected_money = 0.;
let mut owner_set = HashSet::new();
for book in BookInstance::find()
.filter(book_instance::Column::BalId.eq(id))
.all(state.db_conn.as_ref()).await.unwrap() {
if book.sold_price.is_some() {
owner_set.insert(book.owner_id);
total_sold_books += 1;
total_collected_money += book.sold_price.unwrap();
if book.owner_id == self_owner.id {
total_owned_sold_books += 1;
total_owned_collected_money += book.sold_price.unwrap();
}
}
}
let bal_stats = bal_stats::ActiveModel {
id: NotSet,
bal_id: Set(id),
total_sold_books: Set(total_sold_books),
total_owned_sold_books: Set(total_owned_sold_books),
total_collected_money: Set(total_collected_money),
total_owned_collected_money: Set(total_owned_collected_money),
total_different_owners: Set(owner_set.len().try_into().unwrap())
};
bal_stats.save(state.db_conn.as_ref()).await.unwrap();
(StatusCode::OK, Json(Some(model)))
} else {
(StatusCode::NOT_FOUND, Json(None))
}
@ -349,3 +382,109 @@ pub async fn get_bal_accounting(
}
}
#[derive(Deserialize, Serialize, utoipa::ToSchema)]
pub struct BalAccountingReturnParams {
return_type: ReturnType,
}
#[derive(Deserialize, Serialize, utoipa::ToSchema)]
pub enum ReturnType {
Books,
Money,
All
}
#[derive(IntoParams)]
#[into_params(names("id", "owner_id"), parameter_in = Path)]
#[allow(dead_code)]
pub struct BalAndOwnerByIdParams(u32, u32);
#[axum::debug_handler]
#[utoipa::path(
get,
path = "/bal/{id}/accounting/return/{owner_id}",
params(BalAndOwnerByIdParams),
request_body = BalAccountingReturnParams,
security(("jwt" = [])),
responses(
(status = OK, description = "Successfully returned requested type to owner"),
(status = CONFLICT, description = "Books and money have already been returned to the owner, or no money nor books were owed"),
(status = NOT_FOUND, description = "No bal or owner with this id exists in the database"),
(status = FORBIDDEN, description = "You don't own the specified bal or owner"),
),
summary = "Return books and/or money to an owner",
description = "Return books and/or money to an owner",
tag = "bal-api",
)]
pub async fn return_to_owner(
State(state): State<Arc<AppState>>,
claims: Claims,
Path((id, owner_id)): Path<(u32, u32)>,
Json(payload): Json<BalAccountingReturnParams>
) -> StatusCode {
if let Ok(Some(bal)) = Bal::find_by_id(id).one(state.db_conn.as_ref()).await && let Ok(Some(owner)) = Owner::find_by_id(owner_id).one(state.db_conn.as_ref()).await {
if bal.user_id != claims.user_id || owner.user_id != claims.user_id {
StatusCode::FORBIDDEN
} else {
let owner_books = BookInstance::find()
.filter(book_instance::Column::OwnerId.eq(owner.id))
.filter(book_instance::Column::BalId.eq(bal.id))
.all(state.db_conn.as_ref()).await.unwrap();
if owner_books.is_empty() {
return StatusCode::CONFLICT;
}
let mut book_delete_query = BookInstance::delete_many()
.filter(book_instance::Column::OwnerId.eq(owner.id))
.filter(book_instance::Column::BalId.eq(bal.id));
book_delete_query = match payload.return_type {
ReturnType::Books => book_delete_query.filter(book_instance::Column::SoldPrice.is_null()),
ReturnType::Money => book_delete_query.filter(book_instance::Column::SoldPrice.is_not_null()),
ReturnType::All => book_delete_query
};
let _ = book_delete_query.exec(state.db_conn.as_ref()).await;
StatusCode::OK
}
} else {
StatusCode::NOT_FOUND
}
}
#[axum::debug_handler]
#[utoipa::path(
get,
path = "/bal/{id}/stats",
params(BalByIdParams),
security(("jwt" = [])),
responses(
(status = OK, body = bal_stats::Model, description = "Found bal stats with corresponding ID in the database"),
(status = CONFLICT, description = "The specified BAL is not ended yet, can't get stats"),
(status = NOT_FOUND, description = "No bal with this id exists in the database"),
(status = FORBIDDEN, description = "You don't own the specified bal"),
),
summary = "Get a bal's stats by its ID",
description = "Get a bal's stats from its ID",
tag = "bal-api",
)]
pub async fn get_stats_by_bal_id(
State(state): State<Arc<AppState>>,
claims: Claims,
Path(id): Path<u32>,
) -> (StatusCode, Json<Option<bal_stats::Model>>) {
if let Ok(Some(bal)) = Bal::find_by_id(id).one(state.db_conn.as_ref()).await {
if !bal.user_id == claims.user_id {
(StatusCode::FORBIDDEN, Json(None))
} else if bal.state != BalState::Ended {
(StatusCode::CONFLICT, Json(None))
} else {
if let Ok(Some(stats)) = BalStats::find().filter(bal_stats::Column::BalId.eq(bal.id)).one(state.db_conn.as_ref()).await {
(StatusCode::OK, Json(Some(stats)))
} else {
(StatusCode::INTERNAL_SERVER_ERROR, Json(None))
}
}
} else {
(StatusCode::NOT_FOUND, Json(None))
}
}