Compare commits
No commits in common. "31d5fd2b83dbcad5f73289583f2330882e41a08e" and "55b318b2f17b6c74caac16eb1b22b3ee7c690202" have entirely different histories.
31d5fd2b83
...
55b318b2f1
9 changed files with 36 additions and 119 deletions
11
docs/Item.md
11
docs/Item.md
|
@ -64,14 +64,3 @@ variants:
|
||||||
```
|
```
|
||||||
|
|
||||||
This will mark any item variant as expired if it's older than 30 days.
|
This will mark any item variant as expired if it's older than 30 days.
|
||||||
|
|
||||||
### Barcodes
|
|
||||||
You can associate barcodes with your item variants. This is useful for Quick Adding Items.
|
|
||||||
|
|
||||||
```yml
|
|
||||||
name: "Water"
|
|
||||||
variants:
|
|
||||||
regular:
|
|
||||||
name: "Regular Water"
|
|
||||||
barcodes: [12345678]
|
|
||||||
```
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ CREATE TABLE flows (
|
||||||
ended timestamptz,
|
ended timestamptz,
|
||||||
"next" UUID,
|
"next" UUID,
|
||||||
produced UUID[],
|
produced UUID[],
|
||||||
FOREIGN KEY("next") REFERENCES flows(id)
|
FOREIGN KEY "next" REFERENCES flows(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE flow_notes (
|
CREATE TABLE flow_notes (
|
||||||
|
@ -14,7 +14,7 @@ CREATE TABLE flow_notes (
|
||||||
time timestamptz NOT NULL DEFAULT current_timestamp,
|
time timestamptz NOT NULL DEFAULT current_timestamp,
|
||||||
content TEXT NOT NULL,
|
content TEXT NOT NULL,
|
||||||
on_flow UUID NOT NULL,
|
on_flow UUID NOT NULL,
|
||||||
FOREIGN KEY(on_flow) REFERENCES flows(id)
|
FOREIGN KEY on_flow REFERENCES flows(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE transactions (
|
CREATE TABLE transactions (
|
||||||
|
@ -22,7 +22,7 @@ CREATE TABLE transactions (
|
||||||
created timestamptz NOT NULL DEFAULT current_timestamp,
|
created timestamptz NOT NULL DEFAULT current_timestamp,
|
||||||
item TEXT NOT NULL,
|
item TEXT NOT NULL,
|
||||||
variant TEXT NOT NULL,
|
variant TEXT NOT NULL,
|
||||||
price DOUBLE PRECISION,
|
price NUMERIC(2),
|
||||||
origin TEXT,
|
origin TEXT,
|
||||||
"location" TEXT,
|
"location" TEXT,
|
||||||
note TEXT,
|
note TEXT,
|
||||||
|
|
3
rocket.toml
Normal file
3
rocket.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[default]
|
||||||
|
address = "0.0.0.0"
|
||||||
|
port = 8080
|
|
@ -15,8 +15,10 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"variants": {
|
"variants": {
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"minProperties": 1,
|
|
||||||
"title": "Item Variant",
|
"title": "Item Variant",
|
||||||
"description": "A Variant of an Item",
|
"description": "A Variant of an Item",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
@ -34,14 +36,6 @@
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"title": "Expiry days",
|
"title": "Expiry days",
|
||||||
"description": "Number of days until this item variant is considered expired."
|
"description": "Number of days until this item variant is considered expired."
|
||||||
},
|
|
||||||
"barcodes": {
|
|
||||||
"type": "array",
|
|
||||||
"title": "Associated Barcodes",
|
|
||||||
"description": "Associated Barcodes",
|
|
||||||
"items": {
|
|
||||||
"type": "number",
|
|
||||||
"title": "Barcode"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl ItemDB {
|
||||||
|
|
||||||
/// Retrieves an item by name
|
/// Retrieves an item by name
|
||||||
pub fn get_item(&self, item: &str) -> Option<&Item> {
|
pub fn get_item(&self, item: &str) -> Option<&Item> {
|
||||||
self.index.get(&item.to_lowercase())
|
self.index.get(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all items
|
/// Get all items
|
||||||
|
|
35
src/item.rs
35
src/item.rs
|
@ -28,37 +28,20 @@ pub struct Item {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// Category of the Item
|
/// Category of the Item
|
||||||
pub category: Option<String>,
|
pub category: Option<String>,
|
||||||
/// Image
|
|
||||||
pub image_path: Option<String>,
|
|
||||||
/// The variants of an Item.
|
/// The variants of an Item.
|
||||||
/// Each key of the `HashMap<_>` is the ID of a variant and contains a `Variant`
|
/// Each key of the `HashMap<_>` is the ID of a variant and contains a `Variant`
|
||||||
pub variants: HashMap<String, Variant>,
|
pub variants: HashMap<String, Variant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_image(path: &std::path::Path) -> Option<String> {
|
|
||||||
let parent = path.parent()?;
|
|
||||||
let file_name = path.file_stem()?.to_str()?;
|
|
||||||
|
|
||||||
for ext in ["jpg", "jpeg", "webp", "png"] {
|
|
||||||
let mut img_file = parent.to_path_buf();
|
|
||||||
img_file.push(&format!("{file_name}.{ext}"));
|
|
||||||
|
|
||||||
if img_file.exists() {
|
|
||||||
return Some(img_file.display().to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Item {
|
impl Item {
|
||||||
/// Creates a new `Item` from a parsed markdown document
|
/// Creates a new `Item` from a parsed markdown document
|
||||||
pub fn new(doc: &mdq::Document) -> Self {
|
pub fn new(doc: &mdq::Document) -> Self {
|
||||||
let path = std::path::Path::new(&doc.path);
|
let id = std::path::Path::new(&doc.path)
|
||||||
|
.file_stem()
|
||||||
let id = path.file_stem().unwrap().to_str().unwrap().to_lowercase();
|
.unwrap()
|
||||||
|
.to_str()
|
||||||
let image_path = get_image(path);
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
let category = doc
|
let category = doc
|
||||||
.frontmatter
|
.frontmatter
|
||||||
|
@ -103,7 +86,6 @@ impl Item {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
category,
|
category,
|
||||||
image_path,
|
|
||||||
variants,
|
variants,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,11 +131,6 @@ impl Item {
|
||||||
|
|
||||||
json!({
|
json!({
|
||||||
"uuid": self.id,
|
"uuid": self.id,
|
||||||
"image": if self.image_path.is_some() {
|
|
||||||
Some(format!("/item/{}/image", self.id))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"category": self.category,
|
"category": self.category,
|
||||||
"variants": variants
|
"variants": variants
|
||||||
|
|
28
src/main.rs
28
src/main.rs
|
@ -74,29 +74,6 @@ macro_rules! get_locations {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static FLOW_INFO: OnceCell<JSONStore<FlowInfo>> = OnceCell::const_new();
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! get_flows {
|
|
||||||
() => {
|
|
||||||
if let Some(client) = $crate::FLOW_INFO.get() {
|
|
||||||
client
|
|
||||||
} else {
|
|
||||||
let mut flows: $crate::json_store::JSONStore<$crate::flow::FlowInfo> =
|
|
||||||
$crate::JSONStore::new("./flows");
|
|
||||||
|
|
||||||
let flow_keys: Vec<_> = flows.keys().cloned().collect();
|
|
||||||
for flow_key in flow_keys {
|
|
||||||
let flow = flows.get_mut(&flow_key).unwrap();
|
|
||||||
flow.id = flow_key.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
$crate::FLOW_INFO.set(flows).unwrap();
|
|
||||||
$crate::FLOW_INFO.get().unwrap()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ░░░░░░░░░░▀▀▀██████▄▄▄░░░░░░░░░░
|
// ░░░░░░░░░░▀▀▀██████▄▄▄░░░░░░░░░░
|
||||||
// ░░░░░░░░░░░░░░░░░▀▀▀████▄░░░░░░░
|
// ░░░░░░░░░░░░░░░░░▀▀▀████▄░░░░░░░
|
||||||
// ░░░░░░░░░░▄███████▀░░░▀███▄░░░░░
|
// ░░░░░░░░░░▄███████▀░░░▀███▄░░░░░
|
||||||
|
@ -136,7 +113,7 @@ async fn rocket() -> _ {
|
||||||
let config = config::get_config();
|
let config = config::get_config();
|
||||||
let itemdb = get_itemdb!().clone();
|
let itemdb = get_itemdb!().clone();
|
||||||
let locations = get_locations!().clone();
|
let locations = get_locations!().clone();
|
||||||
let flows = get_flows!().clone();
|
let flows: JSONStore<FlowInfo> = JSONStore::new("./flows");
|
||||||
integrity::verify_integrity(&config, &flows, &locations, &itemdb).await;
|
integrity::verify_integrity(&config, &flows, &locations, &itemdb).await;
|
||||||
|
|
||||||
rocket::build()
|
rocket::build()
|
||||||
|
@ -173,8 +150,7 @@ async fn rocket() -> _ {
|
||||||
routes::flow::active_flows_route,
|
routes::flow::active_flows_route,
|
||||||
routes::flow::flow_api_route,
|
routes::flow::flow_api_route,
|
||||||
routes::flow::create_flow_note_route,
|
routes::flow::create_flow_note_route,
|
||||||
routes::flow::flow_notes_route,
|
routes::flow::flow_notes_route
|
||||||
routes::item::item_image_route
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.manage(itemdb)
|
.manage(itemdb)
|
||||||
|
|
|
@ -9,7 +9,6 @@ use std::str::FromStr;
|
||||||
pub use demand::*;
|
pub use demand::*;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use location::*;
|
pub use location::*;
|
||||||
use rocket::fs::NamedFile;
|
|
||||||
use rocket::post;
|
use rocket::post;
|
||||||
use rocket::serde::json::Json;
|
use rocket::serde::json::Json;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -63,17 +62,6 @@ pub fn item_route(
|
||||||
Ok(item.api_json())
|
Ok(item.api_json())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/item/<item_id>/image")]
|
|
||||||
pub async fn item_image_route(item_id: &str, itemdb: &State<ItemDB>) -> Option<NamedFile> {
|
|
||||||
let item = itemdb.get_item(item_id)?;
|
|
||||||
|
|
||||||
if let Some(img_path) = &item.image_path {
|
|
||||||
return Some(NamedFile::open(img_path).await.ok()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns all variants of an Item
|
/// Returns all variants of an Item
|
||||||
#[get("/item/<item_id>/variants")]
|
#[get("/item/<item_id>/variants")]
|
||||||
pub fn item_variants_page(
|
pub fn item_variants_page(
|
||||||
|
|
|
@ -43,8 +43,6 @@ pub struct Variant {
|
||||||
pub min: Option<i64>,
|
pub min: Option<i64>,
|
||||||
/// Days until expiry
|
/// Days until expiry
|
||||||
pub expiry: Option<i64>,
|
pub expiry: Option<i64>,
|
||||||
/// Associated barcodes
|
|
||||||
pub barcodes: Option<Vec<i64>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Variant {
|
impl Variant {
|
||||||
|
@ -71,13 +69,6 @@ impl Variant {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get("expiry")
|
.get("expiry")
|
||||||
.map(|x| x.as_i64().unwrap()),
|
.map(|x| x.as_i64().unwrap()),
|
||||||
barcodes: json.as_mapping().unwrap().get("barcodes").map(|x| {
|
|
||||||
x.as_sequence()
|
|
||||||
.unwrap()
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| x.as_i64().unwrap())
|
|
||||||
.collect()
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,8 +294,7 @@ impl Variant {
|
||||||
"variant": self.variant,
|
"variant": self.variant,
|
||||||
"name": self.name,
|
"name": self.name,
|
||||||
"min": self.min,
|
"min": self.min,
|
||||||
"expiry": self.expiry,
|
"expiry": self.expiry
|
||||||
"barcodes": self.barcodes
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue