Compare commits

..

No commits in common. "31d5fd2b83dbcad5f73289583f2330882e41a08e" and "55b318b2f17b6c74caac16eb1b22b3ee7c690202" have entirely different histories.

9 changed files with 36 additions and 119 deletions

View file

@ -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]
```

View file

@ -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
View file

@ -0,0 +1,3 @@
[default]
address = "0.0.0.0"
port = 8080

View file

@ -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"
} }
} }
} }

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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(

View file

@ -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
}) })
} }
} }