From d5a82fff6a2a15411bcb6583e9fd782b7230e61c Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Mon, 7 Oct 2024 21:23:16 +0200
Subject: [PATCH 01/10] fix

---
 migrations/0000_init.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/migrations/0000_init.sql b/migrations/0000_init.sql
index d617aa1..fc53325 100644
--- a/migrations/0000_init.sql
+++ b/migrations/0000_init.sql
@@ -6,7 +6,7 @@ CREATE TABLE flows (
     ended timestamptz,
     "next" UUID,
     produced UUID[],
-    FOREIGN KEY "next" REFERENCES flows(id)
+    FOREIGN KEY("next") REFERENCES flows(id)
 );
 
 CREATE TABLE flow_notes (

From b4df75dcb6cfb52f868ae790ede64c3d3a017ba9 Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Mon, 7 Oct 2024 21:28:07 +0200
Subject: [PATCH 02/10] fix

---
 migrations/0000_init.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/migrations/0000_init.sql b/migrations/0000_init.sql
index fc53325..df24d2d 100644
--- a/migrations/0000_init.sql
+++ b/migrations/0000_init.sql
@@ -14,7 +14,7 @@ CREATE TABLE flow_notes (
     time timestamptz NOT NULL DEFAULT current_timestamp,
     content TEXT NOT NULL,
     on_flow UUID NOT NULL,
-    FOREIGN KEY on_flow REFERENCES flows(id)
+    FOREIGN KEY(on_flow) REFERENCES flows(id)
 );
 
 CREATE TABLE transactions (

From 3eea2be3e8b08ccb1e7fd15562c2ea0dafec4384 Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Mon, 7 Oct 2024 21:35:50 +0200
Subject: [PATCH 03/10] fix

---
 src/main.rs | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/main.rs b/src/main.rs
index bdcfa6e..bcd321f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -74,6 +74,30 @@ 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()
+        }
+    };
+}
+
 // ░░░░░░░░░░▀▀▀██████▄▄▄░░░░░░░░░░
 // ░░░░░░░░░░░░░░░░░▀▀▀████▄░░░░░░░
 // ░░░░░░░░░░▄███████▀░░░▀███▄░░░░░
@@ -113,7 +137,7 @@ async fn rocket() -> _ {
     let config = config::get_config();
     let itemdb = get_itemdb!().clone();
     let locations = get_locations!().clone();
-    let flows: JSONStore<FlowInfo> = JSONStore::new("./flows");
+    let flows = get_flows!().clone();
     integrity::verify_integrity(&config, &flows, &locations, &itemdb).await;
 
     rocket::build()

From 64e23cc4ab69c3ed6282229c4a90ce96e6c9f3eb Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Mon, 7 Oct 2024 21:53:11 +0200
Subject: [PATCH 04/10] fix

---
 migrations/0000_init.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/migrations/0000_init.sql b/migrations/0000_init.sql
index df24d2d..f38a7f4 100644
--- a/migrations/0000_init.sql
+++ b/migrations/0000_init.sql
@@ -22,7 +22,7 @@ CREATE TABLE transactions (
     created timestamptz NOT NULL DEFAULT current_timestamp,
     item TEXT NOT NULL,
     variant TEXT NOT NULL,
-    price NUMERIC(2),
+    price DOUBLE PRECISION,
     origin TEXT,
     "location" TEXT,
     note TEXT,

From b057c46cbe3e2db13fd895cec63e0ee83728bf7b Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Tue, 8 Oct 2024 10:42:21 +0200
Subject: [PATCH 05/10] add barcodes

---
 src/variant.rs | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/variant.rs b/src/variant.rs
index 03f3dc5..82a3400 100644
--- a/src/variant.rs
+++ b/src/variant.rs
@@ -43,6 +43,8 @@ pub struct Variant {
     pub min: Option<i64>,
     /// Days until expiry
     pub expiry: Option<i64>,
+    /// Associated barcodes
+    pub barcodes: Option<Vec<i64>>
 }
 
 impl Variant {
@@ -69,6 +71,9 @@ impl Variant {
                 .unwrap()
                 .get("expiry")
                 .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()
+            })
         }
     }
 
@@ -294,7 +299,8 @@ impl Variant {
             "variant": self.variant,
             "name": self.name,
             "min": self.min,
-            "expiry": self.expiry
+            "expiry": self.expiry,
+            "barcodes": self.barcodes
         })
     }
 }

From 6c6ee93fbf5c02aedddfb6ffdc84b336b02b8441 Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Thu, 17 Oct 2024 11:33:03 +0200
Subject: [PATCH 06/10] update

---
 docs/Item.md | 11 +++++++++++
 rocket.toml  |  3 ---
 2 files changed, 11 insertions(+), 3 deletions(-)
 delete mode 100644 rocket.toml

diff --git a/docs/Item.md b/docs/Item.md
index 4b9caf9..5f8d280 100644
--- a/docs/Item.md
+++ b/docs/Item.md
@@ -64,3 +64,14 @@ variants:
 ```
 
 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]
+```
diff --git a/rocket.toml b/rocket.toml
deleted file mode 100644
index 30421bb..0000000
--- a/rocket.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-[default]
-address = "0.0.0.0"
-port = 8080

From 4c0769199c9872ad5de5d04ac2faf5d012c3db07 Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Fri, 18 Oct 2024 10:57:38 +0200
Subject: [PATCH 07/10] image

---
 src/item.rs            | 35 +++++++++++++++++++++++++++++------
 src/main.rs            |  1 -
 src/routes/item/mod.rs | 12 ++++++++++++
 src/variant.rs         | 10 +++++++---
 4 files changed, 48 insertions(+), 10 deletions(-)

diff --git a/src/item.rs b/src/item.rs
index f08f72e..9fdba58 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -28,20 +28,37 @@ pub struct Item {
     pub name: String,
     /// Category of the Item
     pub category: Option<String>,
+    /// Image
+    pub image_path: Option<String>,
     /// The variants of an Item.
     /// Each key of the `HashMap<_>` is the ID of a variant and contains a `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 {
     /// Creates a new `Item` from a parsed markdown document
     pub fn new(doc: &mdq::Document) -> Self {
-        let id = std::path::Path::new(&doc.path)
-            .file_stem()
-            .unwrap()
-            .to_str()
-            .unwrap()
-            .to_string();
+        let path = std::path::Path::new(&doc.path);
+
+        let id = path.file_stem().unwrap().to_str().unwrap().to_string();
+
+        let image_path = get_image(path);
 
         let category = doc
             .frontmatter
@@ -86,6 +103,7 @@ impl Item {
             id,
             name,
             category,
+            image_path,
             variants,
         }
     }
@@ -131,6 +149,11 @@ impl Item {
 
         json!({
             "uuid": self.id,
+            "image": if self.image_path.is_some() {
+                Some(format!("/item/{}/image", self.id))
+            } else {
+                None
+            },
             "name": self.name,
             "category": self.category,
             "variants": variants
diff --git a/src/main.rs b/src/main.rs
index bcd321f..1a63e15 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -74,7 +74,6 @@ macro_rules! get_locations {
     };
 }
 
-
 pub static FLOW_INFO: OnceCell<JSONStore<FlowInfo>> = OnceCell::const_new();
 
 #[macro_export]
diff --git a/src/routes/item/mod.rs b/src/routes/item/mod.rs
index 0985e06..cc149a0 100644
--- a/src/routes/item/mod.rs
+++ b/src/routes/item/mod.rs
@@ -9,6 +9,7 @@ use std::str::FromStr;
 pub use demand::*;
 pub use error::*;
 pub use location::*;
+use rocket::fs::NamedFile;
 use rocket::post;
 use rocket::serde::json::Json;
 use serde::Deserialize;
@@ -62,6 +63,17 @@ pub fn item_route(
     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
 #[get("/item/<item_id>/variants")]
 pub fn item_variants_page(
diff --git a/src/variant.rs b/src/variant.rs
index 82a3400..be78064 100644
--- a/src/variant.rs
+++ b/src/variant.rs
@@ -44,7 +44,7 @@ pub struct Variant {
     /// Days until expiry
     pub expiry: Option<i64>,
     /// Associated barcodes
-    pub barcodes: Option<Vec<i64>>
+    pub barcodes: Option<Vec<i64>>,
 }
 
 impl Variant {
@@ -72,8 +72,12 @@ impl Variant {
                 .get("expiry")
                 .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()
-            })
+                x.as_sequence()
+                    .unwrap()
+                    .into_iter()
+                    .map(|x| x.as_i64().unwrap())
+                    .collect()
+            }),
         }
     }
 

From 2823eea3ee97296a8a1bd8b4b5aa316031a5c7bc Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Sat, 19 Oct 2024 20:13:37 +0200
Subject: [PATCH 08/10] fix

---
 src/main.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/main.rs b/src/main.rs
index 1a63e15..2309ea5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -173,7 +173,8 @@ async fn rocket() -> _ {
                 routes::flow::active_flows_route,
                 routes::flow::flow_api_route,
                 routes::flow::create_flow_note_route,
-                routes::flow::flow_notes_route
+                routes::flow::flow_notes_route,
+                routes::item::item_image_route
             ],
         )
         .manage(itemdb)

From 1cc0b61c356177747ce44e580b72cb687b25b461 Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Sun, 20 Oct 2024 04:04:50 +0200
Subject: [PATCH 09/10] update

---
 schema/item.json | 46 ++++++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/schema/item.json b/schema/item.json
index 9f27fc2..3ce9805 100644
--- a/schema/item.json
+++ b/schema/item.json
@@ -15,27 +15,33 @@
             "type": "string"
         },
         "variants": {
-            "type": "array",
-            "minItems": 1,
-            "items": {
-                "type": "object",
-                "title": "Item Variant",
-                "description": "A Variant of an Item",
-                "properties": {
-                    "name": {
-                        "type": "string",
-                        "title": "Variant Name",
-                        "description": "The name of the Variant"
-                    },
-                    "min": {
+            "type": "object",
+            "minProperties": 1,
+            "title": "Item Variant",
+            "description": "A Variant of an Item",
+            "properties": {
+                "name": {
+                    "type": "string",
+                    "title": "Variant Name",
+                    "description": "The name of the Variant"
+                },
+                "min": {
+                    "type": "number",
+                    "title": "Minimum inventory",
+                    "description": "The minimum amount of inventory for an Item. Thre actual inventory amount should always be higher than that."
+                },
+                "expiry": {
+                    "type": "number",
+                    "title": "Expiry days",
+                    "description": "Number of days until this item variant is considered expired."
+                },
+                "barcodes": {
+                    "type": "array",
+                    "title": "Associated Barcodes",
+                    "description": "Associated Barcodes",
+                    "items": {
                         "type": "number",
-                        "title": "Minimum inventory",
-                        "description": "The minimum amount of inventory for an Item. Thre actual inventory amount should always be higher than that."
-                    },
-                    "expiry": {
-                        "type": "number",
-                        "title": "Expiry days",
-                        "description": "Number of days until this item variant is considered expired."
+                        "title": "Barcode"
                     }
                 }
             }

From 31d5fd2b83dbcad5f73289583f2330882e41a08e Mon Sep 17 00:00:00 2001
From: JMARyA <jmarya@hydrar.de>
Date: Sun, 20 Oct 2024 22:13:10 +0200
Subject: [PATCH 10/10] fix

---
 src/db.rs   | 2 +-
 src/item.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/db.rs b/src/db.rs
index 5c441a5..0999819 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -27,7 +27,7 @@ impl ItemDB {
 
     /// Retrieves an item by name
     pub fn get_item(&self, item: &str) -> Option<&Item> {
-        self.index.get(item)
+        self.index.get(&item.to_lowercase())
     }
 
     /// Get all items
diff --git a/src/item.rs b/src/item.rs
index 9fdba58..a407b4a 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -56,7 +56,7 @@ impl Item {
     pub fn new(doc: &mdq::Document) -> Self {
         let path = std::path::Path::new(&doc.path);
 
-        let id = path.file_stem().unwrap().to_str().unwrap().to_string();
+        let id = path.file_stem().unwrap().to_str().unwrap().to_lowercase();
 
         let image_path = get_image(path);