work
This commit is contained in:
parent
9da4ef072c
commit
ba61580adb
7 changed files with 177 additions and 179 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -484,6 +484,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"tokio",
|
||||
"toml",
|
||||
"uuid",
|
||||
"web-base",
|
||||
]
|
||||
|
||||
|
@ -2649,9 +2650,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.6.1"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560"
|
||||
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"rand",
|
||||
|
@ -2661,9 +2662,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uuid-macro-internal"
|
||||
version = "1.6.1"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f49e7f3f3db8040a100710a11932239fd30697115e2ba4107080d8252939845e"
|
||||
checksum = "9881bea7cbe687e36c9ab3b778c36cd0487402e270304e8b1296d5085303c1a2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -15,4 +15,5 @@ serde = { version = "1.0.195", features = ["derive"] }
|
|||
serde_json = "1.0.111"
|
||||
tokio = { version = "1.35.1", features = ["full"] }
|
||||
toml = "0.8.8"
|
||||
uuid = { version = "1.8.0", features = ["v4"] }
|
||||
web-base = "0.2.2"
|
||||
|
|
126
src/item.rs
126
src/item.rs
|
@ -3,6 +3,33 @@ use std::collections::HashSet;
|
|||
use futures::TryStreamExt;
|
||||
use mongodb::{bson::doc, Collection};
|
||||
|
||||
// todo : api key auth
|
||||
|
||||
// case: itemset
|
||||
// items describe generic top level structure
|
||||
|
||||
// case: item variants
|
||||
// specific instance of an item (real world)
|
||||
// possibly deviating attrs
|
||||
|
||||
// case: import
|
||||
// made / bought an item -> supply
|
||||
// check in with attrs -> uuid (transaction)
|
||||
// commited to db
|
||||
|
||||
// case: export
|
||||
// used an item -> demand
|
||||
// mark as used
|
||||
// update db
|
||||
|
||||
// ITEM
|
||||
// VARIANTS
|
||||
// QUANTIZATION
|
||||
// IMPORT / EXPORT
|
||||
// DEPENDENCIES
|
||||
// DEMAND STATS
|
||||
// SEASONAL REVIEWS
|
||||
|
||||
macro_rules! collect_results {
|
||||
($res:expr) => {{
|
||||
let mut ret = vec![];
|
||||
|
@ -15,6 +42,14 @@ macro_rules! collect_results {
|
|||
}};
|
||||
}
|
||||
|
||||
macro_rules! get_mongo {
|
||||
() => {
|
||||
mongodb::Client::with_uri_str(std::env::var("DB_URI").unwrap())
|
||||
.await
|
||||
.unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
pub struct ItemVariantEntry {
|
||||
pub item_name: String,
|
||||
|
@ -70,11 +105,10 @@ impl Item {
|
|||
let quantities: Collection<ItemInventoryEntry> =
|
||||
self.db.database("cdb").collection("item_quantities");
|
||||
|
||||
let mut found =
|
||||
quantities
|
||||
.find(doc! { "item_name": self.item.name.clone()}, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut found = quantities
|
||||
.find(doc! { "item_name": self.item.name.clone()}, None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
collect_results!(found)
|
||||
}
|
||||
|
@ -83,11 +117,10 @@ impl Item {
|
|||
let quantities: Collection<ItemInventoryEntry> =
|
||||
self.db.database("cdb").collection("item_quantities");
|
||||
|
||||
let mut found =
|
||||
quantities
|
||||
.find(doc! { "item_name": self.item.name.clone()}, None)
|
||||
.await
|
||||
.unwrap();
|
||||
let mut found = quantities
|
||||
.find(doc! { "item_name": self.item.name.clone()}, None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut hashset = HashSet::new();
|
||||
|
||||
|
@ -139,6 +172,14 @@ impl Item {
|
|||
ret
|
||||
}
|
||||
|
||||
pub fn variant(&self, variant: &str) -> Option<Variant> {
|
||||
// todo : check if avail
|
||||
Some(Variant {
|
||||
item: self.item.name.clone(),
|
||||
variant: variant.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn add_variant(&self, name: &str) {
|
||||
let variants: Collection<ItemVariantEntry> =
|
||||
self.db.database("cdb").collection("item_variants");
|
||||
|
@ -155,6 +196,66 @@ impl Item {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Price(String);
|
||||
|
||||
impl Price {
|
||||
fn new(price: &str) -> Self {
|
||||
// todo : implement
|
||||
|
||||
Self(price.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Price {
|
||||
fn from(val: std::string::String) -> Self {
|
||||
Self::new(&val)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Variant {
|
||||
pub item: String,
|
||||
pub variant: String,
|
||||
}
|
||||
|
||||
pub struct Transaction {}
|
||||
|
||||
impl Transaction {
|
||||
pub fn new(item: &str, variant: &str, price: Price, origin: &str) -> Self {
|
||||
// todo : implement
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn as_doc(self) -> mongodb::bson::Document {
|
||||
mongodb::bson::doc! {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
pub async fn supply(&self, amount: usize, price: Price, origin: &str) -> String {
|
||||
// todo : implement db transactions
|
||||
let db = get_mongo!();
|
||||
let col: mongodb::Collection<mongodb::bson::Document> =
|
||||
db.database("cdb").collection("transactions");
|
||||
|
||||
let mut transactions = vec![];
|
||||
for _ in 0..amount {
|
||||
transactions.push(Transaction::new(
|
||||
&self.item,
|
||||
&self.variant,
|
||||
price.clone(),
|
||||
origin,
|
||||
));
|
||||
}
|
||||
|
||||
for transaction in transactions {
|
||||
let r = col.insert_one(transaction.as_doc(), None).await;
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ItemDB {
|
||||
index: mdq::Index,
|
||||
mongodb: mongodb::Client,
|
||||
|
@ -165,7 +266,7 @@ impl ItemDB {
|
|||
// scan for markdown item entries
|
||||
let index = mdq::Index::new(dir, true);
|
||||
let mongodb = mongodb::Client::with_uri_str(mongodb).await.unwrap();
|
||||
|
||||
/*
|
||||
for item in &index.documents {
|
||||
let item = ItemEntry::new(item.clone());
|
||||
log::info!("Adding item {} to DB", item.name);
|
||||
|
@ -180,11 +281,12 @@ impl ItemDB {
|
|||
} else {
|
||||
// todo : update values
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
Self { index, mongodb }
|
||||
}
|
||||
|
||||
/// Retrieves an item by name
|
||||
pub fn get_item(&self, item: &str) -> Option<Item> {
|
||||
Some(Item::new(
|
||||
self.mongodb.clone(),
|
||||
|
|
|
@ -36,11 +36,8 @@ async fn main() -> std::io::Result<()> {
|
|||
web_base::map!(web_base::Site::new(), |app: actix_web::App<_>| {
|
||||
app.app_data(itemdb.clone())
|
||||
.service(index)
|
||||
.service(routes::item::item_page)
|
||||
.service(routes::item::variant_pages::add_item_variant_page)
|
||||
.service(routes::item::variant_pages::add_item_variant_page_post)
|
||||
.service(routes::item::inventory_page::add_item_inventory_page)
|
||||
.service(routes::item::inventory_page::add_item_inventory_page_post)
|
||||
.service(routes::item::supply_route)
|
||||
.service(routes::item::item_variants_page)
|
||||
})
|
||||
.bind(("0.0.0.0".to_string(), 8080))?
|
||||
.run()
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
use actix_web::{get, post, HttpRequest, Responder};
|
||||
use maud::html;
|
||||
|
||||
use crate::item;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
struct AddinventoryForm {
|
||||
variant: String,
|
||||
origin: String,
|
||||
price: f64,
|
||||
}
|
||||
|
||||
#[post("/item/{item_id}/inventory/add")]
|
||||
pub async fn add_item_inventory_page_post(
|
||||
r: HttpRequest,
|
||||
f: actix_web::web::Form<AddinventoryForm>,
|
||||
) -> impl Responder {
|
||||
let id = r.match_info().query("item_id");
|
||||
let itemdb: &actix_web::web::Data<item::ItemDB> = r.app_data().unwrap();
|
||||
let item = itemdb.get_item(id).unwrap();
|
||||
let rec_id = item.add_inventory(&f.variant, &f.origin, f.price).await;
|
||||
|
||||
// todo : generate receipts
|
||||
|
||||
web_base::redirect(&format!("/receipt/{}", rec_id))
|
||||
}
|
||||
|
||||
#[get("/item/{item_id}/inventory/add")]
|
||||
pub async fn add_item_inventory_page(r: HttpRequest) -> impl Responder {
|
||||
let id = r.match_info().query("item_id");
|
||||
|
||||
let itemdb: &actix_web::web::Data<item::ItemDB> = r.app_data().unwrap();
|
||||
|
||||
let item = itemdb.get_item(id).unwrap();
|
||||
let item_variants = item.get_variants().await;
|
||||
|
||||
// todo : get previous origins
|
||||
let item_origins = item.get_origins().await;
|
||||
|
||||
let content = html!(
|
||||
div class="bg-white p-8 rounded shadow-md max-w-md grid items-center justify-center m-auto mt-5" {
|
||||
h1 class="text-2xl font-bold mb-4" { "Add Item inventory" };
|
||||
form action=(format!("/item/{}/inventory/add", id)) method="post" {
|
||||
div {
|
||||
label class="text-sm font-medium text-gray-600 mr-3" for="variant" { "Variant:" };
|
||||
select class="mt-1 p-2 border border-gray-300 rounded focus:outline-none focus:border-blue-500" id="variant" name="variant" {
|
||||
@for variant in item_variants {
|
||||
option value=(variant) { (variant) };
|
||||
};
|
||||
};
|
||||
};
|
||||
br;
|
||||
label class="text-sm font-medium text-gray-600" for="origin" { "Origin:" };
|
||||
input class="mt-1 p-2 border border-gray-300 rounded focus:outline-none focus:border-blue-500" type="text" name="origin" list="origin_options" placeholder="Origin";
|
||||
datalist id="origin_options" {
|
||||
@for origin in item_origins {
|
||||
option value=(origin);
|
||||
}
|
||||
};
|
||||
br;
|
||||
label class="text-sm font-medium text-gray-600" for="price" { "Price: "};
|
||||
input class="mt-1 p-2 border border-gray-300 rounded focus:outline-none focus:border-blue-500" type="number" step="0.01" name="price" placeholder="0.00";
|
||||
br;
|
||||
input class="hover:cursor-pointer bg-blue-500 text-white rounded px-4 py-2 mt-5" type="submit" name="submit" value="Add";
|
||||
};
|
||||
};
|
||||
).into_string();
|
||||
|
||||
web_base::build_site(&r, "Add Item inventory", &content)
|
||||
}
|
|
@ -1,50 +1,60 @@
|
|||
use actix_web::{get, HttpRequest, Responder};
|
||||
use actix_web::post;
|
||||
use actix_web::{get, HttpRequest, HttpResponse, Responder};
|
||||
use maud::html;
|
||||
pub mod inventory_page;
|
||||
pub mod variant_pages;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::item;
|
||||
|
||||
#[get("/item/{item_id}")]
|
||||
pub async fn item_page(r: HttpRequest) -> impl Responder {
|
||||
let id = r.match_info().query("item_id");
|
||||
println!("{}", id);
|
||||
|
||||
let itemdb: &actix_web::web::Data<item::ItemDB> = r.app_data().unwrap();
|
||||
|
||||
let item = itemdb.get_item(id).unwrap();
|
||||
|
||||
let content =
|
||||
html!(
|
||||
div class="bg-gray-100 min-h-screen min-w-screen items-center justify-center py-5" {
|
||||
div class="w-screen px-5" {
|
||||
div {
|
||||
p class="mb-2 font-bold text-2xl" { (format!("Item : {}", item.item.name)) };
|
||||
p class="font-bold" { (format!("Category: {}", item.item.category))};
|
||||
};
|
||||
div class="mt-5" {
|
||||
// (button("Add Variant", &format!("/item/{}/variant/add", item.item.name)))
|
||||
// (button("Add inventory", &format!("/item/{}/inventory/add", item.item.name)));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
div class="mt-5 px-5" {
|
||||
h1 class="text-2xl font-bold mb-4" { "Variants" };
|
||||
@for variant in item.get_variants().await {
|
||||
p class="mb-2" { (variant) };
|
||||
}
|
||||
@for q in item.get_inventory_entries().await {
|
||||
div class="p-2" {
|
||||
p { (format!("Variant {}", q.variant_name))};
|
||||
p { (format!("Origin {}", q.origin))};
|
||||
p { (format!("Price {}", q.price))};
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
)
|
||||
.into_string();
|
||||
|
||||
web_base::build_site(&r, "Item", &content)
|
||||
macro_rules! get_itemdb {
|
||||
($req:expr) => {{
|
||||
let itemdb: &actix_web::web::Data<item::ItemDB> = $req.app_data().unwrap();
|
||||
itemdb
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct SupplyForm {
|
||||
item: String,
|
||||
variant: String,
|
||||
amount: Option<usize>,
|
||||
price: String,
|
||||
origin: String,
|
||||
}
|
||||
|
||||
#[post("/supply")]
|
||||
pub async fn supply_route(
|
||||
req: HttpRequest,
|
||||
form: actix_web::web::Form<SupplyForm>,
|
||||
) -> impl Responder {
|
||||
let itemdb = get_itemdb!(req);
|
||||
println!("{form:?}");
|
||||
let variant = itemdb
|
||||
.get_item(&form.item)
|
||||
.unwrap()
|
||||
.variant(&form.variant)
|
||||
.unwrap();
|
||||
let transaction_id = variant
|
||||
.supply(
|
||||
form.amount.unwrap_or(1),
|
||||
form.price.clone().into(),
|
||||
&form.origin,
|
||||
)
|
||||
.await;
|
||||
actix_web::HttpResponse::Ok().json(serde_json::json!({"uuid": transaction_id}))
|
||||
}
|
||||
|
||||
#[get("/item/{item_id}/variants")]
|
||||
pub async fn item_variants_page(r: HttpRequest) -> impl Responder {
|
||||
let id = r.match_info().query("item_id");
|
||||
|
||||
let itemdb = get_itemdb!(r);
|
||||
|
||||
let item = itemdb.get_item(id);
|
||||
|
||||
let variants = item.unwrap().get_variants().await;
|
||||
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"item": id,
|
||||
"variants": variants
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
use actix_web::{get, post, HttpRequest, Responder};
|
||||
use maud::html;
|
||||
|
||||
use crate::item;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
struct AddVariantForm {
|
||||
variant_name: String,
|
||||
}
|
||||
|
||||
#[post("/item/{item_id}/variant/add")]
|
||||
pub async fn add_item_variant_page_post(
|
||||
r: HttpRequest,
|
||||
f: actix_web::web::Form<AddVariantForm>,
|
||||
) -> impl Responder {
|
||||
let id = r.match_info().query("item_id");
|
||||
let itemdb: &actix_web::web::Data<item::ItemDB> = r.app_data().unwrap();
|
||||
let item = itemdb.get_item(id).unwrap();
|
||||
item.add_variant(&f.variant_name).await;
|
||||
|
||||
web_base::redirect(&format!("/item/{}", id))
|
||||
}
|
||||
|
||||
#[get("/item/{item_id}/variant/add")]
|
||||
pub async fn add_item_variant_page(r: HttpRequest) -> impl Responder {
|
||||
let id = r.match_info().query("item_id");
|
||||
|
||||
let itemdb: &actix_web::web::Data<item::ItemDB> = r.app_data().unwrap();
|
||||
|
||||
let item = itemdb.get_item(id).unwrap();
|
||||
|
||||
let content = html!(
|
||||
div class="bg-white p-8 rounded shadow-md max-w-md grid items-center justify-center m-auto mt-5" {
|
||||
h1 class="text-2xl font-bold mb-4" { "Add Variant for " (item.item.name) };
|
||||
form action=(format!("/item/{}/variant/add", id)) method="post" {
|
||||
input class="mt-1 p-2 border border-gray-300 rounded focus:outline-none focus:border-blue-500" type="text" name="variant_name" placeholder="Name" { };
|
||||
input class="ml-5 hover:cursor-pointer bg-blue-500 text-white rounded px-4 py-2 mt-5" type="submit" name="submit" value="Add";
|
||||
};
|
||||
};
|
||||
).into_string();
|
||||
|
||||
web_base::build_site(&r, "Add Item Variant", &content)
|
||||
}
|
Loading…
Reference in a new issue