postgres
This commit is contained in:
parent
584ffb6b11
commit
1faa3b9668
19 changed files with 1058 additions and 1244 deletions
|
@ -1,18 +1,16 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use mongod::{reference_of, vec_to_api, Model, Referencable, Sort, ToAPI};
|
||||
use mongodb::bson::doc;
|
||||
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, FallibleApiResponse, Token},
|
||||
transaction::{Price, Transaction},
|
||||
routes::{api_error, vec_to_api, FallibleApiResponse, ToAPI, Token},
|
||||
transaction::Transaction,
|
||||
};
|
||||
|
||||
use super::{item::SupplyForm, ApiError};
|
||||
|
@ -42,16 +40,11 @@ pub async fn active_flows_route(
|
|||
|
||||
let flowinfo = flows.get(id).ok_or_else(|| api_error("Flow not found"))?;
|
||||
|
||||
let flow = Flow::find(
|
||||
doc! {
|
||||
"kind": flowinfo.reference(),
|
||||
"done": { "$not": { "$type": "object" } }
|
||||
},
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let flow: Vec<Flow> = sqlx::query_as("SELECT * FROM flows WHERE kind = $1 AND ended IS NULL")
|
||||
.bind(&flowinfo.id)
|
||||
.fetch_all(get_pg!())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
Ok(json!(vec_to_api(&flow).await))
|
||||
}
|
||||
|
@ -85,9 +78,10 @@ pub async fn create_flow(
|
|||
// verify valid input transactions
|
||||
if let Some(input) = &form.input {
|
||||
for t in input {
|
||||
let t = Transaction::get(t)
|
||||
.await
|
||||
.ok_or_else(|| api_error(&format!("No such transaction {t}")))?;
|
||||
let t =
|
||||
Transaction::get(&uuid::Uuid::from_str(t).map_err(|_| api_error("Invalid UUID"))?)
|
||||
.await
|
||||
.ok_or_else(|| api_error(&format!("No such transaction {t}")))?;
|
||||
|
||||
let item_variant = format!("{}::{}", t.item, t.variant);
|
||||
|
||||
|
@ -109,14 +103,13 @@ pub async fn create_flow(
|
|||
if input_ref.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(input_ref.iter().map(|x| x.reference()).collect())
|
||||
Some(input_ref.iter().map(|x| x.id).collect())
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
for t in input_ref {
|
||||
t.consume(Price::zero(), &format!("flow::{kind}::{}", flow._id))
|
||||
.await;
|
||||
t.consume(0.0, &format!("flow::{kind}::{}", flow.id)).await;
|
||||
}
|
||||
|
||||
Ok(flow)
|
||||
|
@ -139,12 +132,12 @@ pub async fn create_flow_route(
|
|||
flows: &State<JSONStore<FlowInfo>>,
|
||||
) -> FallibleApiResponse {
|
||||
let flow = create_flow(id, flows, &form).await?;
|
||||
Ok(json!({"uuid": flow._id }))
|
||||
Ok(json!({"uuid": flow.id }))
|
||||
}
|
||||
|
||||
#[get("/flow/<id>")]
|
||||
pub async fn flow_api_route(id: &str) -> FallibleApiResponse {
|
||||
let flow = Flow::get(id)
|
||||
let flow = Flow::get(&uuid::Uuid::from_str(id).map_err(|_| api_error("Invalid UUID"))?)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No such flow"))?;
|
||||
Ok(flow.api().await)
|
||||
|
@ -152,11 +145,11 @@ pub async fn flow_api_route(id: &str) -> FallibleApiResponse {
|
|||
|
||||
#[post("/flow/<id>/end", data = "<form>")]
|
||||
pub async fn end_flow_route(id: &str, form: Json<EndFlow>) -> FallibleApiResponse {
|
||||
let flow = Flow::get(id)
|
||||
let flow = Flow::get(&uuid::Uuid::from_str(id).map_err(|_| api_error("Invalid UUID"))?)
|
||||
.await
|
||||
.ok_or_else(|| api_error("Flow not found"))?;
|
||||
|
||||
if flow.done.is_some() {
|
||||
if flow.ended.is_some() {
|
||||
return Err(api_error("Flow already ended"));
|
||||
}
|
||||
|
||||
|
@ -175,17 +168,17 @@ pub async fn continue_flow_route(
|
|||
flows: &State<JSONStore<FlowInfo>>,
|
||||
form: Json<CreateFlow>,
|
||||
) -> FallibleApiResponse {
|
||||
let this_flow = Flow::get(id)
|
||||
let this_flow = Flow::get(&uuid::Uuid::from_str(id).map_err(|_| api_error("Invalid UUID"))?)
|
||||
.await
|
||||
.ok_or_else(|| api_error("Flow not found"))?;
|
||||
|
||||
if this_flow.done.is_some() {
|
||||
if this_flow.ended.is_some() {
|
||||
return Err(api_error("Flow already ended"));
|
||||
}
|
||||
|
||||
// create next flow
|
||||
let next_kind = flows
|
||||
.get(this_flow.kind.id())
|
||||
.get(&this_flow.kind)
|
||||
.ok_or_else(|| api_error("Flow not found"))?
|
||||
.next
|
||||
.clone()
|
||||
|
@ -195,20 +188,12 @@ pub async fn continue_flow_route(
|
|||
// end current flow
|
||||
this_flow.continue_next(&next_flow).await;
|
||||
|
||||
Ok(json!({"uuid": next_flow._id}))
|
||||
Ok(json!({"uuid": next_flow.id}))
|
||||
}
|
||||
|
||||
#[get("/flow/<id>/notes")]
|
||||
pub async fn flow_notes_route(id: &str) -> FallibleApiResponse {
|
||||
let notes = FlowNote::find(
|
||||
doc! {
|
||||
"on_flow": reference_of!(Flow, id).ok_or_else(|| api_error("No such flow"))?
|
||||
},
|
||||
None,
|
||||
Some(doc! { "timestamp": Sort::Descending }),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let notes = FlowNote::find_of(id).await;
|
||||
|
||||
Ok(json!(vec_to_api(¬es).await))
|
||||
}
|
||||
|
@ -222,8 +207,8 @@ pub struct NoteAdd {
|
|||
pub async fn create_flow_note_route(id: &str, form: Json<NoteAdd>) -> FallibleApiResponse {
|
||||
let note = FlowNote::create(
|
||||
&form.content,
|
||||
reference_of!(Flow, id).ok_or_else(|| api_error("No such flow"))?,
|
||||
&uuid::Uuid::from_str(id).map_err(|_| api_error("Invalid UUID"))?,
|
||||
)
|
||||
.await;
|
||||
Ok(json!({"uuid": note._id }))
|
||||
Ok(json!({"uuid": note.id }))
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use mongod::{Model, ToAPI};
|
||||
use std::str::FromStr;
|
||||
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::{get, post, State};
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::check_auth;
|
||||
use crate::config::{Config, Webhook};
|
||||
use crate::item::Item;
|
||||
use crate::routes::Token;
|
||||
use crate::routes::{ToAPI, Token};
|
||||
use crate::variant::Variant;
|
||||
use crate::{check_auth, get_itemdb};
|
||||
use crate::{
|
||||
db::ItemDB,
|
||||
routes::{api_error, FallibleApiResponse},
|
||||
|
@ -20,7 +20,7 @@ use super::{item_does_not_exist_error, variant_does_not_exist_error};
|
|||
pub struct DemandForm {
|
||||
uuid: String,
|
||||
destination: String,
|
||||
price: String,
|
||||
price: f64,
|
||||
}
|
||||
|
||||
/// Consumes a Transaction with Price and Destination
|
||||
|
@ -29,11 +29,8 @@ pub async fn demand_route(f: Json<DemandForm>, t: Token, c: &State<Config>) -> F
|
|||
check_auth!(t, c);
|
||||
|
||||
let transaction = Variant::demand(
|
||||
&f.uuid,
|
||||
f.price
|
||||
.clone()
|
||||
.try_into()
|
||||
.map_err(|()| api_error("Price malformed"))?,
|
||||
&uuid::Uuid::from_str(&f.uuid).map_err(|_| api_error("Invalid UUID"))?,
|
||||
f.price,
|
||||
&f.destination,
|
||||
)
|
||||
.await
|
||||
|
@ -45,8 +42,8 @@ pub async fn demand_route(f: Json<DemandForm>, t: Token, c: &State<Config>) -> F
|
|||
}
|
||||
|
||||
if let Some(url) = &hook.item_below_minimum {
|
||||
let variant = Item::get(&transaction.item)
|
||||
.await
|
||||
let variant = get_itemdb!()
|
||||
.get_item(&transaction.item)
|
||||
.unwrap()
|
||||
.variant(&transaction.variant)
|
||||
.unwrap();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use mongod::{vec_to_api, ToAPI};
|
||||
use rocket::{get, State};
|
||||
use serde_json::json;
|
||||
|
||||
|
@ -9,7 +8,7 @@ use crate::{
|
|||
config::Config,
|
||||
json_store::JSONStore,
|
||||
location::Location,
|
||||
routes::{api_error, FallibleApiResponse, Token},
|
||||
routes::{api_error, vec_to_api, FallibleApiResponse, ToAPI, Token},
|
||||
transaction::Transaction,
|
||||
};
|
||||
|
||||
|
@ -121,11 +120,6 @@ pub async fn location_inventory(
|
|||
}
|
||||
|
||||
Ok(json!(
|
||||
vec_to_api(
|
||||
&Transaction::in_location(location)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No such location"))?
|
||||
)
|
||||
.await
|
||||
vec_to_api(&Transaction::in_location(location).await).await
|
||||
))
|
||||
}
|
||||
|
|
|
@ -4,12 +4,11 @@ mod location;
|
|||
mod stat;
|
||||
mod supply;
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use demand::*;
|
||||
pub use error::*;
|
||||
pub use location::*;
|
||||
use mongod::reference_of;
|
||||
use mongod::Model;
|
||||
use mongod::ToAPI;
|
||||
use rocket::post;
|
||||
use rocket::serde::json::Json;
|
||||
use serde::Deserialize;
|
||||
|
@ -25,7 +24,9 @@ use crate::check_auth;
|
|||
use crate::config::Config;
|
||||
use crate::db::get_items_without_min_satisfied;
|
||||
use crate::db::ItemDB;
|
||||
use crate::location::Location;
|
||||
use crate::get_locations;
|
||||
use crate::get_pg;
|
||||
use crate::routes::ToAPI;
|
||||
use crate::routes::Token;
|
||||
use crate::transaction::Transaction;
|
||||
|
||||
|
@ -91,9 +92,11 @@ pub async fn transaction_route(
|
|||
) -> FallibleApiResponse {
|
||||
check_auth!(t, c);
|
||||
|
||||
let t = Transaction::get(transaction)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No transaction with this UUID"))?;
|
||||
let t = Transaction::get(
|
||||
&uuid::Uuid::from_str(&transaction).map_err(|_| api_error("Invalid UUID"))?,
|
||||
)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No transaction with this UUID"))?;
|
||||
Ok(t.api().await)
|
||||
}
|
||||
|
||||
|
@ -184,16 +187,16 @@ pub struct MoveTransaction {
|
|||
#[post("/transaction/<id>/move", data = "<form>")]
|
||||
pub async fn move_transaction_route(id: &str, form: Json<MoveTransaction>) -> FallibleApiResponse {
|
||||
let new_loc = &form.to;
|
||||
Transaction::get(id)
|
||||
.await
|
||||
.ok_or_else(|| api_error("No such transaction"))?
|
||||
.change()
|
||||
.location(if form.to.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(reference_of!(Location, new_loc).ok_or_else(|| api_error("No such location"))?)
|
||||
})
|
||||
.update()
|
||||
let locations = get_locations!();
|
||||
|
||||
if !locations.contains_key(new_loc) {
|
||||
return Err(api_error("No such location"));
|
||||
}
|
||||
|
||||
sqlx::query("UPDATE transactions SET location = $1 WHERE id = $2")
|
||||
.bind(new_loc)
|
||||
.bind(uuid::Uuid::from_str(id).map_err(|_| api_error("Invalid UUID"))?)
|
||||
.execute(get_pg!())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -73,7 +73,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.value;
|
||||
total_price += t.price;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use mongod::ToAPI;
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::{get, post, State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -6,7 +5,7 @@ use serde_json::json;
|
|||
|
||||
use crate::check_auth;
|
||||
use crate::config::{Config, Webhook};
|
||||
use crate::routes::Token;
|
||||
use crate::routes::{vec_to_api, ToAPI, Token};
|
||||
use crate::{
|
||||
db::ItemDB,
|
||||
routes::{api_error, FallibleApiResponse},
|
||||
|
@ -18,7 +17,7 @@ use super::{item_does_not_exist_error, variant_does_not_exist_error};
|
|||
pub struct SupplyForm {
|
||||
pub item: String,
|
||||
pub variant: String,
|
||||
pub price: String,
|
||||
pub price: f64,
|
||||
pub origin: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub note: Option<String>,
|
||||
|
@ -42,10 +41,7 @@ pub async fn supply_route(
|
|||
|
||||
let transaction = variant
|
||||
.supply(
|
||||
form.price
|
||||
.clone()
|
||||
.try_into()
|
||||
.map_err(|()| api_error("Price malformed"))?,
|
||||
form.price,
|
||||
form.origin.as_deref(),
|
||||
form.location.as_deref(),
|
||||
form.note.as_deref(),
|
||||
|
@ -58,7 +54,7 @@ pub async fn supply_route(
|
|||
}
|
||||
}
|
||||
|
||||
Ok(json!({"uuid": transaction._id}))
|
||||
Ok(json!({"uuid": transaction.id}))
|
||||
}
|
||||
|
||||
/// Returns a list of Transaction UUIDs for the Item Variant
|
||||
|
@ -104,7 +100,7 @@ pub async fn inventory_route(
|
|||
item.inventory().await
|
||||
};
|
||||
|
||||
Ok(json!(mongod::vec_to_api(&transactions).await))
|
||||
Ok(json!(vec_to_api(&transactions).await))
|
||||
}
|
||||
|
||||
/// Returns current active Transactions for Item Variant
|
||||
|
@ -126,7 +122,7 @@ pub async fn inventory_route_variant(
|
|||
|
||||
let transactions = variant.inventory().await;
|
||||
|
||||
Ok(json!(mongod::vec_to_api(&transactions).await))
|
||||
Ok(json!(vec_to_api(&transactions).await))
|
||||
}
|
||||
|
||||
/// Returns statistics for the Item Variant
|
||||
|
|
|
@ -37,3 +37,20 @@ 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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue