simplify
This commit is contained in:
2
rust/Cargo.lock
generated
2
rust/Cargo.lock
generated
@@ -626,6 +626,8 @@ version = "0.25.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0bab19cef8a7fe1c18a43e881793bfc9d4ea984befec3ae5bd0415abf3ecf00"
|
checksum = "b0bab19cef8a7fe1c18a43e881793bfc9d4ea984befec3ae5bd0415abf3ecf00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"axum-core",
|
||||||
|
"http",
|
||||||
"itoa",
|
"itoa",
|
||||||
"maud_macros",
|
"maud_macros",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ version = "0.3"
|
|||||||
|
|
||||||
[dependencies.maud]
|
[dependencies.maud]
|
||||||
version = "0.25"
|
version = "0.25"
|
||||||
|
features = [
|
||||||
|
"axum",
|
||||||
|
]
|
||||||
|
|
||||||
[dependencies.uuid]
|
[dependencies.uuid]
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
use maud::{html, Markup};
|
use maud::{html, Markup};
|
||||||
|
|
||||||
pub struct Home {
|
pub struct Home;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Home {
|
impl Home {
|
||||||
pub fn build() -> Self {
|
pub fn build() -> Markup {
|
||||||
let doc: Markup = html!(
|
html!(
|
||||||
div id="home" class={"p-8" "max-w-xl"} {
|
div id="home" class={"p-8" "max-w-xl"} {
|
||||||
p {
|
p {
|
||||||
a href="/inventory/" { "Inventory" }
|
a href="/inventory/" { "Inventory" }
|
||||||
@@ -15,14 +13,6 @@ impl Home {
|
|||||||
a href="/trips/" { "Trips" }
|
a href="/trips/" { "Trips" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Home> for Markup {
|
|
||||||
fn from(val: Home) -> Self {
|
|
||||||
val.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,15 @@ use crate::models::*;
|
|||||||
use crate::ClientState;
|
use crate::ClientState;
|
||||||
use uuid::{uuid, Uuid};
|
use uuid::{uuid, Uuid};
|
||||||
|
|
||||||
pub struct Inventory {
|
pub struct Inventory;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Inventory {
|
impl Inventory {
|
||||||
pub async fn build(state: ClientState, categories: Vec<Category>) -> Result<Self, Error> {
|
pub async fn build(state: ClientState, categories: Vec<Category>) -> Result<Markup, 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" {
|
||||||
div ."col-span-2" {
|
div ."col-span-2" {
|
||||||
(InventoryCategoryList::build(&state, &categories).into_markup())
|
(InventoryCategoryList::build(&state, &categories))
|
||||||
}
|
}
|
||||||
div ."col-span-2" {
|
div ."col-span-2" {
|
||||||
h1 ."text-2xl" ."mb-5" ."text-center" { "Items" }
|
h1 ."text-2xl" ."mb-5" ."text-center" { "Items" }
|
||||||
@@ -22,37 +20,29 @@ impl Inventory {
|
|||||||
(InventoryItemList::build(&state, categories.iter().find(|category| category.id == active_category_id)
|
(InventoryItemList::build(&state, categories.iter().find(|category| category.id == active_category_id)
|
||||||
.ok_or(Error::NotFoundError { description: format!("no category with id {}", active_category_id) })?
|
.ok_or(Error::NotFoundError { description: format!("no category with id {}", active_category_id) })?
|
||||||
.items())
|
.items())
|
||||||
.into_markup())
|
)
|
||||||
}
|
}
|
||||||
(InventoryNewItemForm::build(&state, &categories).into_markup())
|
(InventoryNewItemForm::build(&state, &categories))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Self { doc })
|
Ok(doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Inventory> for Markup {
|
pub struct InventoryCategoryList;
|
||||||
fn from(val: Inventory) -> Self {
|
|
||||||
val.doc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InventoryCategoryList {
|
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InventoryCategoryList {
|
impl InventoryCategoryList {
|
||||||
pub fn build(state: &ClientState, categories: &Vec<Category>) -> Self {
|
pub fn build(state: &ClientState, categories: &Vec<Category>) -> Markup {
|
||||||
let biggest_category_weight: u32 = categories
|
let biggest_category_weight: u32 = categories
|
||||||
.iter()
|
.iter()
|
||||||
.map(Category::total_weight)
|
.map(Category::total_weight)
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(1);
|
.unwrap_or(1);
|
||||||
|
|
||||||
let doc = html!(
|
html!(
|
||||||
div {
|
div {
|
||||||
h1 ."text-2xl" ."mb-5" ."text-center" { "Categories" }
|
h1 ."text-2xl" ."mb-5" ."text-center" { "Categories" }
|
||||||
table
|
table
|
||||||
@@ -146,30 +136,16 @@ impl InventoryCategoryList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_markup(self) -> Markup {
|
|
||||||
self.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<InventoryCategoryList> for Markup {
|
pub struct InventoryItemList;
|
||||||
fn from(val: InventoryCategoryList) -> Self {
|
|
||||||
val.doc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InventoryItemList {
|
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InventoryItemList {
|
impl InventoryItemList {
|
||||||
pub fn build(state: &ClientState, items: &Vec<Item>) -> Self {
|
pub fn build(state: &ClientState, items: &Vec<Item>) -> Markup {
|
||||||
let biggest_item_weight: u32 = items.iter().map(|item| item.weight).max().unwrap_or(1);
|
let biggest_item_weight: u32 = items.iter().map(|item| item.weight).max().unwrap_or(1);
|
||||||
let doc = html!(
|
html!(
|
||||||
div #items {
|
div #items {
|
||||||
@if items.is_empty() {
|
@if items.is_empty() {
|
||||||
p ."text-lg" ."text-center" ."py-5" ."text-gray-400" { "[Empty]" }
|
p ."text-lg" ."text-center" ."py-5" ."text-gray-400" { "[Empty]" }
|
||||||
@@ -305,30 +281,15 @@ impl InventoryItemList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_markup(self) -> Markup {
|
|
||||||
self.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<InventoryItemList> for Markup {
|
pub struct InventoryNewItemForm;
|
||||||
fn from(val: InventoryItemList) -> Self {
|
|
||||||
val.doc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InventoryNewItemForm {
|
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InventoryNewItemForm {
|
impl InventoryNewItemForm {
|
||||||
pub fn build(state: &ClientState, categories: &Vec<Category>) -> Self {
|
pub fn build(state: &ClientState, categories: &Vec<Category>) -> Markup {
|
||||||
let doc = html!(
|
html!(
|
||||||
|
|
||||||
form
|
form
|
||||||
name="new-item"
|
name="new-item"
|
||||||
id="new-item"
|
id="new-item"
|
||||||
@@ -417,24 +378,6 @@ impl InventoryNewItemForm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_markup(self) -> Markup {
|
|
||||||
self.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<InventoryNewItemForm> for Markup {
|
|
||||||
fn from(val: InventoryNewItemForm) -> Self {
|
|
||||||
val.doc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// impl InventoryItemList {
|
|
||||||
// pub fn to_string(self) -> String {
|
|
||||||
// self.doc.into_string()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//ItemList
|
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ pub use home::*;
|
|||||||
pub use inventory::*;
|
pub use inventory::*;
|
||||||
pub use trip::*;
|
pub use trip::*;
|
||||||
|
|
||||||
pub struct Root {
|
pub struct Root;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum TopLevelPage {
|
pub enum TopLevelPage {
|
||||||
Inventory,
|
Inventory,
|
||||||
@@ -19,8 +17,8 @@ pub enum TopLevelPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Root {
|
impl Root {
|
||||||
pub fn build(body: Markup, active_page: &TopLevelPage) -> Self {
|
pub fn build(body: Markup, active_page: &TopLevelPage) -> Markup {
|
||||||
let doc = html!(
|
html!(
|
||||||
(DOCTYPE)
|
(DOCTYPE)
|
||||||
html {
|
html {
|
||||||
head {
|
head {
|
||||||
@@ -61,12 +59,20 @@ impl Root {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
}
|
||||||
Self { doc }
|
}
|
||||||
}
|
|
||||||
|
pub struct ErrorPage;
|
||||||
pub fn into_string(self) -> String {
|
|
||||||
self.doc.into_string()
|
impl ErrorPage {
|
||||||
|
pub fn build(message: &str) -> Markup {
|
||||||
|
Root::build(
|
||||||
|
html!(
|
||||||
|
h1 { "Error" }
|
||||||
|
p { (message) }
|
||||||
|
),
|
||||||
|
&TopLevelPage::None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,36 +3,24 @@ use crate::models::*;
|
|||||||
|
|
||||||
use maud::{html, Markup};
|
use maud::{html, Markup};
|
||||||
|
|
||||||
pub struct TripManager {
|
pub struct TripManager;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TripManager {
|
impl TripManager {
|
||||||
pub fn build(trips: Vec<models::Trip>) -> Self {
|
pub fn build(trips: Vec<models::Trip>) -> Markup {
|
||||||
let doc = html!(
|
html!(
|
||||||
div ."p-8" {
|
div ."p-8" {
|
||||||
(TripTable::build(trips).into_markup())
|
(TripTable::build(trips))
|
||||||
(NewTrip::build().into_markup())
|
(NewTrip::build())
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TripTable {
|
pub struct TripTable;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TripManager> for Markup {
|
|
||||||
fn from(val: TripManager) -> Self {
|
|
||||||
val.doc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TripTable {
|
impl TripTable {
|
||||||
pub fn build(trips: Vec<models::Trip>) -> Self {
|
pub fn build(trips: Vec<models::Trip>) -> Markup {
|
||||||
let doc = html!(
|
html!(
|
||||||
h1 ."text-2xl" ."mb-5" {"Trips"}
|
h1 ."text-2xl" ."mb-5" {"Trips"}
|
||||||
table
|
table
|
||||||
."table"
|
."table"
|
||||||
@@ -83,23 +71,15 @@ impl TripTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_markup(self) -> Markup {
|
|
||||||
self.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NewTrip {
|
pub struct NewTrip;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NewTrip {
|
impl NewTrip {
|
||||||
pub fn build() -> Self {
|
pub fn build() -> Markup {
|
||||||
let doc = html!(
|
html!(
|
||||||
form
|
form
|
||||||
name="new_trip"
|
name="new_trip"
|
||||||
action="/trip/"
|
action="/trip/"
|
||||||
@@ -190,48 +170,32 @@ impl NewTrip {
|
|||||||
{}
|
{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_markup(self) -> Markup {
|
|
||||||
self.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Trip {
|
pub struct Trip;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Trip {
|
impl Trip {
|
||||||
pub fn build(trip: &models::Trip) -> Self {
|
pub fn build(trip: &models::Trip) -> Markup {
|
||||||
let doc = html!(
|
html!(
|
||||||
div ."p-8" {
|
div ."p-8" {
|
||||||
div ."flex" ."flex-row" ."items-center" ."gap-x-3" {
|
div ."flex" ."flex-row" ."items-center" ."gap-x-3" {
|
||||||
h1 ."text-2xl" ."font-semibold"{ (trip.name) }
|
h1 ."text-2xl" ."font-semibold"{ (trip.name) }
|
||||||
}
|
}
|
||||||
div ."my-6" {
|
div ."my-6" {
|
||||||
(TripInfo::build(&trip).into_markup())
|
(TripInfo::build(&trip))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_markup(self) -> Markup {
|
|
||||||
self.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TripInfo {
|
pub struct TripInfo;
|
||||||
doc: Markup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TripInfo {
|
impl TripInfo {
|
||||||
pub fn build(trip: &models::Trip) -> Self {
|
pub fn build(trip: &models::Trip) -> Markup {
|
||||||
let doc = html!(
|
html!(
|
||||||
table
|
table
|
||||||
."table"
|
."table"
|
||||||
."table-auto"
|
."table-auto"
|
||||||
@@ -338,12 +302,6 @@ impl TripInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
|
||||||
Self { doc }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn into_markup(self) -> Markup {
|
|
||||||
self.doc
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
125
rust/src/main.rs
125
rust/src/main.rs
@@ -16,6 +16,8 @@ use sqlx::{
|
|||||||
Pool, Row, Sqlite,
|
Pool, Row, Sqlite,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use maud::Markup;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use futures::TryFutureExt;
|
use futures::TryFutureExt;
|
||||||
@@ -108,10 +110,10 @@ async fn main() -> Result<(), sqlx::Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn root() -> (StatusCode, Html<String>) {
|
async fn root() -> (StatusCode, Markup) {
|
||||||
(
|
(
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Html::from(Root::build(Home::build().into(), &TopLevelPage::None).into_string()),
|
Root::build(Home::build(), &TopLevelPage::None),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +132,7 @@ async fn inventory_active(
|
|||||||
Path(id): Path<Uuid>,
|
Path(id): Path<Uuid>,
|
||||||
State(mut state): State<AppState>,
|
State(mut state): State<AppState>,
|
||||||
Query(inventory_query): Query<InventoryQuery>,
|
Query(inventory_query): Query<InventoryQuery>,
|
||||||
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
) -> Result<(StatusCode, Markup), (StatusCode, Markup)> {
|
||||||
state.client_state.edit_item = inventory_query.edit_item;
|
state.client_state.edit_item = inventory_query.edit_item;
|
||||||
inventory(state, Some(id)).await
|
inventory(state, Some(id)).await
|
||||||
}
|
}
|
||||||
@@ -138,7 +140,7 @@ async fn inventory_active(
|
|||||||
async fn inventory_inactive(
|
async fn inventory_inactive(
|
||||||
State(mut state): State<AppState>,
|
State(mut state): State<AppState>,
|
||||||
Query(inventory_query): Query<InventoryQuery>,
|
Query(inventory_query): Query<InventoryQuery>,
|
||||||
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
) -> Result<(StatusCode, Markup), (StatusCode, Markup)> {
|
||||||
state.client_state.edit_item = inventory_query.edit_item;
|
state.client_state.edit_item = inventory_query.edit_item;
|
||||||
inventory(state, None).await
|
inventory(state, None).await
|
||||||
}
|
}
|
||||||
@@ -146,7 +148,7 @@ async fn inventory_inactive(
|
|||||||
async fn inventory(
|
async fn inventory(
|
||||||
mut state: AppState,
|
mut state: AppState,
|
||||||
active_id: Option<Uuid>,
|
active_id: Option<Uuid>,
|
||||||
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
) -> Result<(StatusCode, Markup), (StatusCode, Markup)> {
|
||||||
state.client_state.active_category_id = active_id;
|
state.client_state.active_category_id = active_id;
|
||||||
|
|
||||||
let mut categories = query("SELECT id,name,description FROM inventoryitemcategories")
|
let mut categories = query("SELECT id,name,description FROM inventoryitemcategories")
|
||||||
@@ -156,36 +158,50 @@ async fn inventory(
|
|||||||
.await
|
.await
|
||||||
// we have two error handling lines here. these are distinct errors
|
// we have two error handling lines here. these are distinct errors
|
||||||
// this one is the SQL error that may arise during the query
|
// this one is the SQL error that may arise during the query
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
ErrorPage::build(&e.to_string()),
|
||||||
|
)
|
||||||
|
})?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Result<Vec<Category>, models::Error>>()
|
.collect::<Result<Vec<Category>, models::Error>>()
|
||||||
// and this one is the model mapping error that may arise e.g. during
|
// and this one is the model mapping error that may arise e.g. during
|
||||||
// reading of the rows
|
// reading of the rows
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?;
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
ErrorPage::build(&e.to_string()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
for category in &mut categories {
|
for category in &mut categories {
|
||||||
category
|
category
|
||||||
.populate_items(&state.database_pool)
|
.populate_items(&state.database_pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?;
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
ErrorPage::build(&e.to_string()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Html::from(
|
Root::build(
|
||||||
Root::build(
|
Inventory::build(state.client_state, categories)
|
||||||
Inventory::build(state.client_state, categories)
|
.await
|
||||||
.await
|
.map_err(|e| match e {
|
||||||
.map_err(|e| match e {
|
Error::NotFoundError { description } => {
|
||||||
Error::NotFoundError { description } => {
|
(StatusCode::NOT_FOUND, ErrorPage::build(&description))
|
||||||
(StatusCode::NOT_FOUND, Html::from(description))
|
}
|
||||||
}
|
_ => (
|
||||||
_ => (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())),
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
})?
|
ErrorPage::build(&e.to_string()),
|
||||||
.into(),
|
),
|
||||||
&TopLevelPage::Inventory,
|
})?,
|
||||||
)
|
&TopLevelPage::Inventory,
|
||||||
.into_string(),
|
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -306,7 +322,7 @@ async fn inventory_item_delete(
|
|||||||
|
|
||||||
// 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, Markup), (StatusCode, Markup)> {
|
||||||
// let pool = SqlitePoolOptions::new()
|
// let pool = SqlitePoolOptions::new()
|
||||||
// .max_connections(5)
|
// .max_connections(5)
|
||||||
// .connect("sqlite:///home/hannes-private/sync/items/items.sqlite")
|
// .connect("sqlite:///home/hannes-private/sync/items/items.sqlite")
|
||||||
@@ -452,7 +468,7 @@ async fn trip_create(
|
|||||||
|
|
||||||
async fn trips(
|
async fn trips(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
) -> Result<(StatusCode, Markup), (StatusCode, Markup)> {
|
||||||
let trips: Vec<models::Trip> = query("SELECT * FROM trips")
|
let trips: Vec<models::Trip> = query("SELECT * FROM trips")
|
||||||
.fetch(&state.database_pool)
|
.fetch(&state.database_pool)
|
||||||
.map_ok(std::convert::TryInto::try_into)
|
.map_ok(std::convert::TryInto::try_into)
|
||||||
@@ -460,25 +476,33 @@ async fn trips(
|
|||||||
.await
|
.await
|
||||||
// we have two error handling lines here. these are distinct errors
|
// we have two error handling lines here. these are distinct errors
|
||||||
// this one is the SQL error that may arise during the query
|
// this one is the SQL error that may arise during the query
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
ErrorPage::build(&e.to_string()),
|
||||||
|
)
|
||||||
|
})?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Result<Vec<models::Trip>, models::Error>>()
|
.collect::<Result<Vec<models::Trip>, models::Error>>()
|
||||||
// and this one is the model mapping error that may arise e.g. during
|
// and this one is the model mapping error that may arise e.g. during
|
||||||
// reading of the rows
|
// reading of the rows
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?;
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
ErrorPage::build(&e.to_string()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Html::from(
|
Root::build(TripManager::build(trips), &TopLevelPage::Trips),
|
||||||
Root::build(TripManager::build(trips).into(), &TopLevelPage::Trips).into_string(),
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trip(
|
async fn trip(
|
||||||
Path(id): Path<Uuid>,
|
Path(id): Path<Uuid>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> Result<(StatusCode, Html<String>), (StatusCode, Html<String>)> {
|
) -> Result<(StatusCode, Markup), (StatusCode, Markup)> {
|
||||||
let mut trip: models::Trip =
|
let mut trip: models::Trip =
|
||||||
query("SELECT id,name,start_date,end_date,state,location,temp_min,temp_max FROM trips WHERE id = ?")
|
query("SELECT id,name,start_date,end_date,state,location,temp_min,temp_max FROM trips WHERE id = ?")
|
||||||
.bind(id.to_string())
|
.bind(id.to_string())
|
||||||
@@ -488,32 +512,31 @@ async fn trip(
|
|||||||
.map_err(|e: sqlx::Error| match e {
|
.map_err(|e: sqlx::Error| match e {
|
||||||
sqlx::Error::RowNotFound => (
|
sqlx::Error::RowNotFound => (
|
||||||
StatusCode::NOT_FOUND,
|
StatusCode::NOT_FOUND,
|
||||||
Html::from(format!("trip with id {} not found", id)),
|
ErrorPage::build(&format!("trip with id {} not found", id)),
|
||||||
),
|
),
|
||||||
_ => (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())),
|
_ => (StatusCode::INTERNAL_SERVER_ERROR, ErrorPage::build(&e.to_string())),
|
||||||
})?
|
})?
|
||||||
.map_err(|e: Error| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?;
|
.map_err(|e: Error| (StatusCode::INTERNAL_SERVER_ERROR, ErrorPage::build(&e.to_string())))?;
|
||||||
|
|
||||||
trip.load_triptypes(&state.database_pool)
|
trip.load_triptypes(&state.database_pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Html::from(e.to_string())))?;
|
.map_err(|e| {
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
ErrorPage::build(&e.to_string()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
Html::from(
|
Root::build(components::Trip::build(&trip), &TopLevelPage::Trips),
|
||||||
Root::build(
|
|
||||||
components::Trip::build(&trip).into_markup(),
|
|
||||||
&TopLevelPage::Trips,
|
|
||||||
)
|
|
||||||
.into_string(),
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn trip_type_remove(
|
async fn trip_type_remove(
|
||||||
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
|
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> Result<Redirect, (StatusCode, Html<String>)> {
|
) -> Result<Redirect, (StatusCode, Markup)> {
|
||||||
let results = query(
|
let results = query(
|
||||||
"DELETE FROM trips_to_triptypes AS ttt
|
"DELETE FROM trips_to_triptypes AS ttt
|
||||||
WHERE ttt.trip_id = ?
|
WHERE ttt.trip_id = ?
|
||||||
@@ -524,12 +547,12 @@ async fn trip_type_remove(
|
|||||||
.bind(type_id.to_string())
|
.bind(type_id.to_string())
|
||||||
.execute(&state.database_pool)
|
.execute(&state.database_pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| (StatusCode::BAD_REQUEST, Html::from(e.to_string())))?;
|
.map_err(|e| (StatusCode::BAD_REQUEST, ErrorPage::build(&e.to_string())))?;
|
||||||
|
|
||||||
if results.rows_affected() == 0 {
|
if results.rows_affected() == 0 {
|
||||||
Err((
|
Err((
|
||||||
StatusCode::NOT_FOUND,
|
StatusCode::NOT_FOUND,
|
||||||
Html::from(format!("type {type_id} is not active for trip {trip_id}")),
|
ErrorPage::build(&format!("type {type_id} is not active for trip {trip_id}")),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(Redirect::to(&format!("/trip/{trip_id}/")))
|
Ok(Redirect::to(&format!("/trip/{trip_id}/")))
|
||||||
@@ -539,8 +562,8 @@ async fn trip_type_remove(
|
|||||||
async fn trip_type_add(
|
async fn trip_type_add(
|
||||||
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
|
Path((trip_id, type_id)): Path<(Uuid, Uuid)>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> Result<Redirect, (StatusCode, Html<String>)> {
|
) -> Result<Redirect, (StatusCode, Markup)> {
|
||||||
let results = query(
|
query(
|
||||||
"INSERT INTO trips_to_triptypes
|
"INSERT INTO trips_to_triptypes
|
||||||
(trip_id, trip_type_id) VALUES (?, ?)",
|
(trip_id, trip_type_id) VALUES (?, ?)",
|
||||||
)
|
)
|
||||||
@@ -560,21 +583,21 @@ async fn trip_type_add(
|
|||||||
// TODO: this is not perfect, as both foreign keys
|
// TODO: this is not perfect, as both foreign keys
|
||||||
// may be responsible for the error. how can we tell
|
// may be responsible for the error. how can we tell
|
||||||
// which one?
|
// which one?
|
||||||
Html::from(format!("invalid id: {}", code.to_string())),
|
ErrorPage::build(&format!("invalid id: {}", code.to_string())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"2067" => {
|
"2067" => {
|
||||||
// SQLITE_CONSTRAINT_UNIQUE
|
// SQLITE_CONSTRAINT_UNIQUE
|
||||||
(
|
(
|
||||||
StatusCode::BAD_REQUEST,
|
StatusCode::BAD_REQUEST,
|
||||||
Html::from(format!(
|
ErrorPage::build(&format!(
|
||||||
"type {type_id} is already active for trip {trip_id}"
|
"type {type_id} is already active for trip {trip_id}"
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => (
|
_ => (
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
Html::from(format!(
|
ErrorPage::build(&format!(
|
||||||
"got error with unknown code: {}",
|
"got error with unknown code: {}",
|
||||||
sqlite_error.to_string()
|
sqlite_error.to_string()
|
||||||
)),
|
)),
|
||||||
@@ -583,7 +606,7 @@ async fn trip_type_add(
|
|||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
Html::from(format!(
|
ErrorPage::build(&format!(
|
||||||
"got error without code: {}",
|
"got error without code: {}",
|
||||||
sqlite_error.to_string()
|
sqlite_error.to_string()
|
||||||
)),
|
)),
|
||||||
@@ -592,7 +615,7 @@ async fn trip_type_add(
|
|||||||
}
|
}
|
||||||
_ => (
|
_ => (
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
Html::from(format!("got unknown error: {}", e.to_string())),
|
ErrorPage::build(&format!("got unknown error: {}", e.to_string())),
|
||||||
),
|
),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ pub enum Error {
|
|||||||
SqlError { description: String },
|
SqlError { description: String },
|
||||||
UuidError { description: String },
|
UuidError { description: String },
|
||||||
NotFoundError { description: String },
|
NotFoundError { description: String },
|
||||||
InvalidEnumError { description: String },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@@ -34,9 +33,6 @@ impl fmt::Display for Error {
|
|||||||
Self::NotFoundError { description } => {
|
Self::NotFoundError { description } => {
|
||||||
write!(f, "Not found: {description}")
|
write!(f, "Not found: {description}")
|
||||||
}
|
}
|
||||||
Self::InvalidEnumError { description } => {
|
|
||||||
write!(f, "Enum error: {description}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user