From 910b10de35fee7fcbb6b6337ab2e1a5625046af9 Mon Sep 17 00:00:00 2001 From: Ninjdai Date: Thu, 14 Aug 2025 17:54:51 +0200 Subject: [PATCH 1/2] feat: update dependencies --- .forgejo/workflows/test.yml | 7 +-- Cargo.lock | 121 ++++++++++++++++++++---------------- Cargo.toml | 6 +- 3 files changed, 72 insertions(+), 62 deletions(-) diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 836b59f..2ff9c04 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -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 diff --git a/Cargo.lock b/Cargo.lock index b898f86..d900966 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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]] diff --git a/Cargo.toml b/Cargo.toml index 3d6e406..670bea8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } From b817d36816f560871f397eff3fed0dd7baef1d01 Mon Sep 17 00:00:00 2001 From: Ninjdai Date: Fri, 15 Aug 2025 13:14:11 +0200 Subject: [PATCH 2/2] feat: book return and bal stats --- src/entities/bal.rs | 2 + src/entities/bal_stats.rs | 38 +++++++++ src/entities/mod.rs | 1 + src/entities/prelude.rs | 1 + src/lib.rs | 2 + src/routes/bal.rs | 159 +++++++++++++++++++++++++++++++++++--- 6 files changed, 193 insertions(+), 10 deletions(-) create mode 100644 src/entities/bal_stats.rs diff --git a/src/entities/bal.rs b/src/entities/bal.rs index 47bbcfd..dd5f8e5 100644 --- a/src/entities/bal.rs +++ b/src/entities/bal.rs @@ -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 for Entity { diff --git a/src/entities/bal_stats.rs b/src/entities/bal_stats.rs new file mode 100644 index 0000000..dfdf601 --- /dev/null +++ b/src/entities/bal_stats.rs @@ -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 for Entity { + fn to() -> RelationDef { + Relation::Bal.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/entities/mod.rs b/src/entities/mod.rs index fd63ca8..57dcee5 100644 --- a/src/entities/mod.rs +++ b/src/entities/mod.rs @@ -1,6 +1,7 @@ pub mod prelude; pub mod bal; +pub mod bal_stats; pub mod book; pub mod book_instance; pub mod owner; diff --git a/src/entities/prelude.rs b/src/entities/prelude.rs index a4e87e2..303c6b4 100644 --- a/src/entities/prelude.rs +++ b/src/entities/prelude.rs @@ -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; diff --git a/src/lib.rs b/src/lib.rs index 39e905d..8a0d8b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -175,6 +175,8 @@ pub async fn run_server(db: Arc, 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)) diff --git a/src/routes/bal.rs b/src/routes/bal.rs index 0fdce03..cc2547f 100644 --- a/src/routes/bal.rs +++ b/src/routes/bal.rs @@ -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>, + claims: Claims, + Path((id, owner_id)): Path<(u32, u32)>, + Json(payload): Json +) -> 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>, + claims: Claims, + Path(id): Path, +) -> (StatusCode, Json>) { + 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)) + } +}