♻️ refactor + location conditions

This commit is contained in:
JMARyA 2025-04-16 04:05:29 +02:00
parent ce9cdc4256
commit 3076ebe6a0
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
19 changed files with 1228 additions and 520 deletions

View file

@ -1,19 +1,19 @@
use rocket::{get, post, serde::json::Json, State};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::{collections::HashMap, str::FromStr};
use crate::{
check_auth,
config::Config,
flow::{Flow, FlowInfo, FlowNote},
get_pg,
json_store::JSONStore,
routes::{api_error, vec_to_api, FallibleApiResponse, ToAPI, Token},
routes::{FallibleApiResponse, Token, api_error},
transaction::Transaction,
};
use based::request::api::{ToAPI, vec_to_api};
use rocket::{State, get, post, serde::json::Json};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::{collections::HashMap, str::FromStr};
use super::{item::SupplyForm, ApiError};
use super::{ApiError, item::SupplyForm};
#[get("/flow/<id>/info")]
pub async fn flow_info(

View file

@ -1,18 +1,18 @@
use std::str::FromStr;
use rocket::serde::json::Json;
use rocket::{get, post, State};
use serde::Deserialize;
use serde_json::json;
use crate::config::{Config, Webhook};
use crate::routes::{ToAPI, Token};
use crate::routes::Token;
use crate::variant::Variant;
use crate::{check_auth, get_itemdb};
use crate::{
db::ItemDB,
routes::{api_error, FallibleApiResponse},
routes::{FallibleApiResponse, api_error},
};
use based::request::api::ToAPI;
use rocket::serde::json::Json;
use rocket::{State, get, post};
use serde::Deserialize;
use serde_json::json;
use super::{item_does_not_exist_error, variant_does_not_exist_error};
@ -23,8 +23,8 @@ pub struct DemandForm {
price: f64,
}
/// Consumes a Transaction with Price and Destination
#[post("/demand", data = "<f>")]
/// Consumes a Transaction with Price and Destination
pub async fn demand_route(f: Json<DemandForm>, t: Token, c: &State<Config>) -> FallibleApiResponse {
check_auth!(t, c);
@ -66,8 +66,8 @@ pub async fn demand_route(f: Json<DemandForm>, t: Token, c: &State<Config>) -> F
Ok(json!({"ok": 1}))
}
/// Returns all consumed transactions for Item Variant
#[get("/item/<item_id>/<variant_id>/demand?<destination>")]
/// Returns all consumed transactions for Item Variant
pub async fn demand_log_route(
item_id: &str,
variant_id: &str,

View file

@ -1,4 +1,4 @@
use crate::routes::{api_error, ApiError};
use crate::routes::{ApiError, api_error};
pub fn item_does_not_exist_error() -> ApiError {
api_error("The item does not exist")

View file

@ -1,16 +1,16 @@
use std::collections::HashMap;
use rocket::{get, State};
use serde_json::json;
use crate::{
check_auth,
config::Config,
json_store::JSONStore,
location::Location,
routes::{api_error, vec_to_api, FallibleApiResponse, ToAPI, Token},
routes::{FallibleApiResponse, Token, api_error},
transaction::Transaction,
};
use based::request::api::{ToAPI, vec_to_api};
use rocket::{State, get};
use serde_json::json;
#[get("/location/<id>")]
pub async fn location_info(
@ -27,6 +27,42 @@ pub async fn location_info(
Ok(loc.api().await)
}
#[get("/location/<id>/warn")]
/// API route returning affected items on a condition mismatch
pub async fn location_condition_warn(
id: &str,
locations: &State<JSONStore<Location>>,
t: Token,
c: &State<Config>,
) -> FallibleApiResponse {
check_auth!(t, c);
let loc = locations
.get(id)
.ok_or_else(|| api_error("No location with that ID"))?;
let transactions = Transaction::in_location(&loc.id).await;
let mut ret = Vec::new();
for t in transactions {
if let Some(item) = t.item_variant().await {
if !item
.satisfy_condition(
loc.conditions
.as_ref()
.ok_or(api_error("Location has no conditions"))?,
)
.await
{
ret.push(t);
}
}
}
Ok(json!(vec_to_api(&ret).await))
}
/// Resolve locations children recursively
async fn location_api_resolve(
id: &str,

View file

@ -6,6 +6,7 @@ mod supply;
use std::str::FromStr;
use based::request::api::ToAPI;
pub use demand::*;
pub use error::*;
pub use location::*;
@ -17,25 +18,24 @@ use serde::Serialize;
pub use stat::*;
pub use supply::*;
use rocket::get;
use rocket::State;
use rocket::get;
use serde_json::json;
use crate::check_auth;
use crate::config::Config;
use crate::db::get_items_without_min_satisfied;
use crate::db::ItemDB;
use crate::db::get_items_without_min_satisfied;
use crate::get_locations;
use crate::get_pg;
use crate::routes::ToAPI;
use crate::routes::Token;
use crate::transaction::Transaction;
use super::api_error;
use crate::routes::FallibleApiResponse;
/// Returns a JSON response with all items in the database.
#[get("/items")]
/// Returns a JSON response with all items in the database.
pub fn get_items_route(itemdb: &State<ItemDB>, t: Token, c: &State<Config>) -> FallibleApiResponse {
check_auth!(t, c);
@ -47,8 +47,8 @@ pub fn get_items_route(itemdb: &State<ItemDB>, t: Token, c: &State<Config>) -> F
Ok(json!({"items": items}))
}
/// Return an API Response for an `Item`
#[get("/item/<item_id>")]
/// Return an API Response for an `Item`
pub fn item_route(
item_id: &str,
itemdb: &State<ItemDB>,
@ -74,8 +74,8 @@ pub async fn item_image_route(item_id: &str, itemdb: &State<ItemDB>) -> Option<N
None
}
/// Returns all variants of an Item
#[get("/item/<item_id>/variants")]
/// Returns all variants of an Item
pub fn item_variants_page(
item_id: &str,
itemdb: &State<ItemDB>,
@ -112,8 +112,8 @@ pub async fn transaction_route(
Ok(t.api().await)
}
/// Returns unique values for a field
#[get("/item/<item_id>/<variant_id>/unique?<field>")]
/// Returns unique values for a field
pub async fn unique_field_route(
item_id: &str,
variant_id: &str,
@ -131,23 +131,28 @@ pub async fn unique_field_route(
.ok_or_else(variant_does_not_exist_error)?;
match field {
"origin" => Ok(json!(variant
.get_unique_origins()
.await
.into_iter()
.filter(|x| !x.starts_with("flow::"))
.collect::<Vec<_>>())),
"destination" => Ok(json!(variant
.get_unique_destinations()
.await
.into_iter()
.filter(|x| !x.starts_with("flow::"))
.collect::<Vec<_>>())),
"origin" => Ok(json!(
variant
.get_unique_origins()
.await
.into_iter()
.filter(|x| !x.starts_with("flow::"))
.collect::<Vec<_>>()
)),
"destination" => Ok(json!(
variant
.get_unique_destinations()
.await
.into_iter()
.filter(|x| !x.starts_with("flow::"))
.collect::<Vec<_>>()
)),
_ => Err(api_error("Unknown field")),
}
}
#[get("/items/expired?<days>")]
/// Get all expired transactions
pub async fn expired_items_route(
days: Option<&str>,
t: Token,
@ -169,6 +174,7 @@ pub async fn expired_items_route(
}
#[get("/items/min")]
/// Return all items without minimum satisfied
pub async fn min_items_route(
itemdb: &State<ItemDB>,
t: Token,
@ -197,6 +203,7 @@ pub struct MoveTransaction {
}
#[post("/transaction/<id>/move", data = "<form>")]
/// Move a transaction to a new location
pub async fn move_transaction_route(id: &str, form: Json<MoveTransaction>) -> FallibleApiResponse {
let new_loc = &form.to;
let locations = get_locations!();

View file

@ -1,4 +1,4 @@
use rocket::{get, State};
use rocket::{State, get};
use serde_json::json;
use crate::check_auth;
@ -6,7 +6,7 @@ use crate::config::Config;
use crate::routes::Token;
use crate::{
db::ItemDB,
routes::{api_error, FallibleApiResponse},
routes::{FallibleApiResponse, api_error},
};
use super::{item_does_not_exist_error, variant_does_not_exist_error};
@ -48,11 +48,13 @@ pub async fn variant_price_latest_by_origin(
.variant(variant_id)
.ok_or_else(variant_does_not_exist_error)?;
Ok(json!(variant
.price_history_by_origin(origin, Some(1))
.await
.first()
.unwrap()))
Ok(json!(
variant
.price_history_by_origin(origin, Some(1))
.await
.first()
.unwrap()
))
}
#[get("/items/stat")]
@ -73,7 +75,7 @@ pub async fn item_stat_route(
let item_var = itemdb.get_item(&item).unwrap().variant(var).unwrap();
for t in item_var.inventory().await {
transaction_count += 1;
total_price += t.price;
total_price += t.price.unwrap_or_default();
}
}
}

View file

@ -1,15 +1,15 @@
use rocket::serde::json::Json;
use rocket::{get, post, State};
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::check_auth;
use crate::config::{Config, Webhook};
use crate::routes::{vec_to_api, ToAPI, Token};
use crate::routes::Token;
use crate::{
db::ItemDB,
routes::{api_error, FallibleApiResponse},
routes::{FallibleApiResponse, api_error},
};
use based::request::api::{ToAPI, vec_to_api};
use rocket::serde::json::Json;
use rocket::{State, get, post};
use serde::{Deserialize, Serialize};
use serde_json::json;
use super::{item_does_not_exist_error, variant_does_not_exist_error};
@ -23,8 +23,8 @@ pub struct SupplyForm {
pub note: Option<String>,
}
/// Route for supply action. Creates a new Transaction for the specified Item Variant.
#[post("/supply", data = "<form>")]
/// Route for supply action. Creates a new Transaction for the specified Item Variant.
pub async fn supply_route(
form: Json<SupplyForm>,
itemdb: &State<ItemDB>,
@ -57,8 +57,8 @@ pub async fn supply_route(
Ok(json!({"uuid": transaction.id}))
}
/// Returns a list of Transaction UUIDs for the Item Variant
#[get("/item/<item_id>/<variant_id>/supply")]
/// Returns a list of Transaction UUIDs for the Item Variant
pub async fn supply_log_route(
item_id: &str,
variant_id: &str,
@ -79,8 +79,8 @@ pub async fn supply_log_route(
Ok(json!(transactions))
}
/// Returns current active Transactions for Item
#[get("/item/<item_id>/inventory?<origin>")]
/// Returns current active Transactions for Item
pub async fn inventory_route(
item_id: &str,
itemdb: &State<ItemDB>,
@ -103,8 +103,8 @@ pub async fn inventory_route(
Ok(json!(vec_to_api(&transactions).await))
}
/// Returns current active Transactions for Item Variant
#[get("/item/<item_id>/<variant_id>/inventory")]
/// Returns current active Transactions for Item Variant
pub async fn inventory_route_variant(
item_id: &str,
variant_id: &str,
@ -125,8 +125,8 @@ pub async fn inventory_route_variant(
Ok(json!(vec_to_api(&transactions).await))
}
/// Returns statistics for the Item Variant
#[get("/item/<item_id>/<variant_id>/stat?<full>")]
/// Returns statistics for the Item Variant
pub async fn variant_stat_route(
item_id: &str,
variant_id: &str,

View file

@ -1,5 +1,5 @@
use rocket::{
http::Status, outcome::Outcome, request::FromRequest, response::status::BadRequest, Request,
Request, http::Status, outcome::Outcome, request::FromRequest, response::status::BadRequest,
};
use serde_json::json;
@ -37,20 +37,3 @@ impl<'r> FromRequest<'r> for Token {
}
}
}
/// A trait to generate a Model API representation in JSON format.
pub trait ToAPI: Sized {
/// Generate public API JSON
fn api(&self) -> impl std::future::Future<Output = serde_json::Value>;
}
/// Converts a slice of items implementing the `ToAPI` trait into a `Vec` of JSON values.
pub async fn vec_to_api(items: &[impl ToAPI]) -> Vec<serde_json::Value> {
let mut ret = Vec::with_capacity(items.len());
for e in items {
ret.push(e.api().await);
}
ret
}