wip
This commit is contained in:
61
rust/Cargo.lock
generated
61
rust/Cargo.lock
generated
@@ -50,6 +50,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"headers",
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"hyper",
|
"hyper",
|
||||||
@@ -88,6 +89,12 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.0"
|
version = "0.21.0"
|
||||||
@@ -405,6 +412,31 @@ dependencies = [
|
|||||||
"hashbrown",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "headers"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.1",
|
||||||
|
"bitflags",
|
||||||
|
"bytes",
|
||||||
|
"headers-core",
|
||||||
|
"http",
|
||||||
|
"httpdate",
|
||||||
|
"mime",
|
||||||
|
"sha1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "headers-core"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
|
||||||
|
dependencies = [
|
||||||
|
"http",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -699,6 +731,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"hyper",
|
"hyper",
|
||||||
"maud",
|
"maud",
|
||||||
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"time",
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -890,7 +923,7 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64 0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -926,6 +959,20 @@ name = "serde"
|
|||||||
version = "1.0.162"
|
version = "1.0.162"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
|
checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.162"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.15",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
@@ -959,6 +1006,17 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
@@ -1458,6 +1516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2"
|
checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies.axum]
|
[dependencies.axum]
|
||||||
version = "0.6.18"
|
version = "0.6.18"
|
||||||
|
features = ["headers"]
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
version = "1.28.0"
|
version = "1.28.0"
|
||||||
@@ -30,6 +31,7 @@ version = "0.25"
|
|||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
features = [
|
features = [
|
||||||
"v4",
|
"v4",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies.sqlx]
|
[dependencies.sqlx]
|
||||||
@@ -41,3 +43,7 @@ version = "0.3.28"
|
|||||||
|
|
||||||
[dependencies.time]
|
[dependencies.time]
|
||||||
version = "0.3.21"
|
version = "0.3.21"
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1.0.162"
|
||||||
|
features = ["derive"]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use maud::{html, Markup};
|
use maud::{html, Markup};
|
||||||
|
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
use crate::State;
|
use crate::ClientState;
|
||||||
use uuid::uuid;
|
use uuid::uuid;
|
||||||
|
|
||||||
pub struct Inventory {
|
pub struct Inventory {
|
||||||
@@ -9,7 +9,7 @@ pub struct Inventory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Inventory {
|
impl Inventory {
|
||||||
pub async fn build(state: State, categories: Vec<Category>) -> Result<Self, Error> {
|
pub async fn build(state: ClientState, categories: Vec<Category>) -> Result<Self, Error> {
|
||||||
let doc = html!(
|
let doc = html!(
|
||||||
div id="pkglist-item-manager" {
|
div id="pkglist-item-manager" {
|
||||||
div ."p-8" ."grid" ."grid-cols-4" ."gap-3" {
|
div ."p-8" ."grid" ."grid-cols-4" ."gap-3" {
|
||||||
@@ -198,6 +198,22 @@ impl InventoryItemList {
|
|||||||
bottom:0;
|
bottom:0;
|
||||||
right:0;", width=(item.weight as f32 / biggest_item_weight as f32 * 100.0))) {}
|
right:0;", width=(item.weight as f32 / biggest_item_weight as f32 * 100.0))) {}
|
||||||
}
|
}
|
||||||
|
td
|
||||||
|
."border"
|
||||||
|
."bg-red-200"
|
||||||
|
."hover:bg-red-400"
|
||||||
|
."cursor-pointer"
|
||||||
|
."w-8"
|
||||||
|
."text-center"
|
||||||
|
{
|
||||||
|
a
|
||||||
|
href = (format!("/inventory/item/{id}/delete", id = item.id))
|
||||||
|
{
|
||||||
|
button {
|
||||||
|
span ."mdi" ."mdi-delete" ."text-xl" {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +237,7 @@ pub struct InventoryNewItemForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InventoryNewItemForm {
|
impl InventoryNewItemForm {
|
||||||
pub async fn build(state: &State, categories: &Vec<Category>) -> Result<Self, Error> {
|
pub async fn build(state: &ClientState, categories: &Vec<Category>) -> Result<Self, Error> {
|
||||||
let doc = html!(
|
let doc = html!(
|
||||||
|
|
||||||
form
|
form
|
||||||
@@ -238,9 +254,9 @@ impl InventoryNewItemForm {
|
|||||||
div ."w-11/12" ."mx-auto" {
|
div ."w-11/12" ."mx-auto" {
|
||||||
div ."pb-8" {
|
div ."pb-8" {
|
||||||
div ."flex" ."flex-row" ."justify-center" ."items-start"{
|
div ."flex" ."flex-row" ."justify-center" ."items-start"{
|
||||||
label for="item-name" .font-bold ."w-1/2" ."p-2" ."text-center" { "Name" }
|
label for="name" .font-bold ."w-1/2" ."p-2" ."text-center" { "Name" }
|
||||||
span ."w-1/2" {
|
span ."w-1/2" {
|
||||||
input type="text" id="item-name" name="name"
|
input type="text" id="new-item-name" name="new-item-name"
|
||||||
."block"
|
."block"
|
||||||
."w-full"
|
."w-full"
|
||||||
."p-2"
|
."p-2"
|
||||||
@@ -256,12 +272,12 @@ impl InventoryNewItemForm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
div ."flex" ."flex-row" ."justify-center" ."items-center" ."pb-8" {
|
div ."flex" ."flex-row" ."justify-center" ."items-center" ."pb-8" {
|
||||||
label for="item-weight" .font-bold ."w-1/2" .text-center { "Weight" }
|
label for="weight" .font-bold ."w-1/2" .text-center { "Weight" }
|
||||||
span ."w-1/2" {
|
span ."w-1/2" {
|
||||||
input
|
input
|
||||||
type="text"
|
type="text"
|
||||||
id="item-weight"
|
id="new-item-weight"
|
||||||
name="weight"
|
name="new-item-weight"
|
||||||
."block"
|
."block"
|
||||||
."w-full"
|
."w-full"
|
||||||
."p-2"
|
."p-2"
|
||||||
@@ -280,8 +296,8 @@ impl InventoryNewItemForm {
|
|||||||
label for="item-category" .font-bold ."w-1/2" .text-center { "Category" }
|
label for="item-category" .font-bold ."w-1/2" .text-center { "Category" }
|
||||||
span ."w-1/2" {
|
span ."w-1/2" {
|
||||||
select
|
select
|
||||||
id="item-category"
|
id="new-item-category-id"
|
||||||
name="category"
|
name="new-item-category-id"
|
||||||
."block"
|
."block"
|
||||||
."w-full"
|
."w-full"
|
||||||
."p-2"
|
."p-2"
|
||||||
|
|||||||
202
rust/src/main.rs
202
rust/src/main.rs
@@ -1,17 +1,28 @@
|
|||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::Path,
|
extract::Path,
|
||||||
http::StatusCode,
|
extract::State,
|
||||||
response::Html,
|
headers,
|
||||||
|
headers::Header,
|
||||||
|
http::{header::HeaderMap, StatusCode},
|
||||||
|
response::{Html, Redirect},
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Router,
|
Form, Router,
|
||||||
};
|
};
|
||||||
use sqlx::sqlite::SqlitePoolOptions;
|
|
||||||
|
use sqlx::{
|
||||||
|
error::DatabaseError,
|
||||||
|
query,
|
||||||
|
sqlite::{SqliteConnectOptions, SqliteError, SqlitePoolOptions},
|
||||||
|
Pool, Sqlite,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
use tracing_subscriber;
|
use tracing_subscriber;
|
||||||
|
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
use uuid::Uuid;
|
use uuid::{uuid, Uuid};
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
@@ -21,13 +32,20 @@ mod models;
|
|||||||
use crate::components::*;
|
use crate::components::*;
|
||||||
use crate::models::*;
|
use crate::models::*;
|
||||||
|
|
||||||
pub struct State {
|
#[derive(Clone)]
|
||||||
|
pub struct AppState {
|
||||||
|
database_pool: Pool<Sqlite>,
|
||||||
|
client_state: ClientState,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ClientState {
|
||||||
pub active_category_id: Option<Uuid>,
|
pub active_category_id: Option<Uuid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl ClientState {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
State {
|
ClientState {
|
||||||
active_category_id: None,
|
active_category_id: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,17 +57,34 @@ async fn main() -> Result<(), sqlx::Error> {
|
|||||||
.with_max_level(tracing::Level::DEBUG)
|
.with_max_level(tracing::Level::DEBUG)
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
let database_pool = SqlitePoolOptions::new()
|
||||||
|
.max_connections(5)
|
||||||
|
.connect_with(
|
||||||
|
SqliteConnectOptions::new()
|
||||||
|
.filename("/home/hannes-private/sync/items/items.sqlite")
|
||||||
|
.pragma("foreign_keys", "1"),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let state = AppState {
|
||||||
|
database_pool,
|
||||||
|
client_state: ClientState::new(),
|
||||||
|
};
|
||||||
|
|
||||||
// build our application with a route
|
// build our application with a route
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(root))
|
.route("/", get(root))
|
||||||
.route("/trips/", get(trips))
|
.route("/trips/", get(trips))
|
||||||
.route("/inventory/", get(inventory_inactive))
|
.route("/inventory/", get(inventory_inactive))
|
||||||
|
.route("/inventory/item/", post(inventory_item_create))
|
||||||
.route("/inventory/category/:id", get(inventory_active))
|
.route("/inventory/category/:id", get(inventory_active))
|
||||||
|
.route("/inventory/item/:id/delete", get(inventory_item_delete))
|
||||||
// .route(
|
// .route(
|
||||||
// "/inventory/category/:id/items",
|
// "/inventory/category/:id/items",
|
||||||
// post(htmx_inventory_category_items),
|
// post(htmx_inventory_category_items),
|
||||||
// );
|
// );
|
||||||
;
|
.with_state(state);
|
||||||
|
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||||
tracing::debug!("listening on {}", addr);
|
tracing::debug!("listening on {}", addr);
|
||||||
@@ -70,33 +105,30 @@ async fn root() -> (StatusCode, Html<String>) {
|
|||||||
|
|
||||||
async fn inventory_active(
|
async fn inventory_active(
|
||||||
Path(id): Path<String>,
|
Path(id): Path<String>,
|
||||||
|
State(state): State<AppState>,
|
||||||
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
||||||
inventory(Some(id)).await
|
inventory(state, Some(id)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inventory_inactive() -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
async fn inventory_inactive(
|
||||||
inventory(None).await
|
State(state): State<AppState>,
|
||||||
|
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
||||||
|
inventory(state, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn inventory(
|
async fn inventory(
|
||||||
|
mut state: AppState,
|
||||||
active_id: Option<String>,
|
active_id: Option<String>,
|
||||||
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
||||||
let mut state: State = State::new();
|
|
||||||
let active_id = active_id
|
let active_id = active_id
|
||||||
.map(|id| Uuid::try_parse(&id))
|
.map(|id| Uuid::try_parse(&id))
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(|e| (StatusCode::BAD_REQUEST, Html::from(e.to_string())))?;
|
.map_err(|e| (StatusCode::BAD_REQUEST, Html::from(e.to_string())))?;
|
||||||
|
|
||||||
state.active_category_id = active_id;
|
state.client_state.active_category_id = active_id;
|
||||||
|
|
||||||
let pool = SqlitePoolOptions::new()
|
let mut categories = query("SELECT id,name,description FROM inventoryitemcategories")
|
||||||
.max_connections(5)
|
.fetch(&state.database_pool)
|
||||||
.connect("sqlite:///home/hannes-private/sync/items/items.sqlite")
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut categories = sqlx::query("SELECT id,name,description FROM inventoryitemcategories")
|
|
||||||
.fetch(&pool)
|
|
||||||
.map_ok(|row| row.try_into())
|
.map_ok(|row| row.try_into())
|
||||||
.try_collect::<Vec<Result<Category, models::Error>>>()
|
.try_collect::<Vec<Result<Category, models::Error>>>()
|
||||||
.await
|
.await
|
||||||
@@ -126,7 +158,7 @@ async fn inventory(
|
|||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Html::from(
|
Html::from(
|
||||||
Root::build(
|
Root::build(
|
||||||
Inventory::build(state, categories)
|
Inventory::build(state.client_state, categories)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?
|
||||||
.into(),
|
.into(),
|
||||||
@@ -137,15 +169,11 @@ async fn inventory(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trips() -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
async fn trips(
|
||||||
let pool = SqlitePoolOptions::new()
|
State(state): State<AppState>,
|
||||||
.max_connections(5)
|
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
||||||
.connect("sqlite:///home/hannes-private/sync/items/items.sqlite")
|
let trips = query("SELECT * FROM trips")
|
||||||
.await
|
.fetch(&state.database_pool)
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let trips = sqlx::query("SELECT * FROM trips")
|
|
||||||
.fetch(&pool)
|
|
||||||
.map_ok(|row| row.try_into())
|
.map_ok(|row| row.try_into())
|
||||||
.try_collect::<Vec<Result<Trip, models::Error>>>()
|
.try_collect::<Vec<Result<Trip, models::Error>>>()
|
||||||
.await
|
.await
|
||||||
@@ -164,6 +192,113 @@ async fn trips() -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct NewItem {
|
||||||
|
#[serde(rename = "new-item-name")]
|
||||||
|
name: String,
|
||||||
|
#[serde(rename = "new-item-weight")]
|
||||||
|
weight: u32,
|
||||||
|
// damn i just love how serde is integrated everywhere, just add a feature to the uuid in
|
||||||
|
// cargo.toml and go
|
||||||
|
#[serde(rename = "new-item-category-id")]
|
||||||
|
category_id: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn inventory_item_create(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Form(new_item): Form<NewItem>,
|
||||||
|
) -> Result<Redirect, (StatusCode, String)> {
|
||||||
|
query(
|
||||||
|
"INSERT INTO inventoryitems
|
||||||
|
(id, name, description, weight, category_id)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?)",
|
||||||
|
)
|
||||||
|
.bind(Uuid::new_v4().to_string())
|
||||||
|
.bind(&new_item.name)
|
||||||
|
.bind("")
|
||||||
|
.bind(new_item.weight)
|
||||||
|
.bind(new_item.category_id.to_string())
|
||||||
|
.execute(&state.database_pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| match e {
|
||||||
|
sqlx::Error::Database(ref error) => {
|
||||||
|
let sqlite_error = error.downcast_ref::<SqliteError>();
|
||||||
|
if let Some(code) = sqlite_error.code() {
|
||||||
|
match &*code {
|
||||||
|
"787" => {
|
||||||
|
// SQLITE_CONSTRAINT_FOREIGNKEY
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
format!("category {id} not found", id = new_item.category_id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"2067" => {
|
||||||
|
// SQLITE_CONSTRAINT_UNIQUE
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
format!(
|
||||||
|
"item with name \"{name}\" already exists in category {id}",
|
||||||
|
name = new_item.name,
|
||||||
|
id = new_item.category_id
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => (
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("got error with unknown code: {}", sqlite_error.to_string()),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("got error without code: {}", sqlite_error.to_string()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
format!("got unknown error: {}", e.to_string()),
|
||||||
|
),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Redirect::to(&format!(
|
||||||
|
"/inventory/category/{id}",
|
||||||
|
id = new_item.category_id
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn inventory_item_delete(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
Path(id): Path<Uuid>,
|
||||||
|
) -> Result<Redirect, (StatusCode, String)> {
|
||||||
|
query(
|
||||||
|
"DELETE FROM inventoryitems
|
||||||
|
WHERE id = ?",
|
||||||
|
)
|
||||||
|
.bind(id.to_string())
|
||||||
|
.execute(&state.database_pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ((StatusCode::BAD_REQUEST, e.to_string())))?;
|
||||||
|
|
||||||
|
Ok(Redirect::to(
|
||||||
|
headers
|
||||||
|
.get("referer")
|
||||||
|
.ok_or((
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"no referer header found".to_string(),
|
||||||
|
))?
|
||||||
|
.to_str()
|
||||||
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
format!("referer could not be converted: {}", e),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
// async fn htmx_inventory_category_items(
|
// async fn htmx_inventory_category_items(
|
||||||
// Path(id): Path<String>,
|
// Path(id): Path<String>,
|
||||||
// ) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
// ) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
||||||
@@ -173,7 +308,8 @@ async fn trips() -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>
|
|||||||
// .await
|
// .await
|
||||||
// .unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
// let items = sqlx::query(&format!(
|
// let items = query(&format!(
|
||||||
|
// //TODO bind this stuff!!!!!!! no sql injection pls
|
||||||
// "SELECT
|
// "SELECT
|
||||||
// i.id, i.name, i.description, i.weight, i.category_id
|
// i.id, i.name, i.description, i.weight, i.category_id
|
||||||
// FROM inventoryitemcategories AS c
|
// FROM inventoryitemcategories AS c
|
||||||
|
|||||||
Reference in New Issue
Block a user