li7y/src/frontend/item_class.rs
Simon Bruder 00d7647187
Switch to sqlx
While diesel has a native rust interface, writing more complex queries
is easier when you can just pass a SQL query string.
2024-07-19 00:05:26 +02:00

254 lines
7.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-FileCopyrightText: 2024 Simon Bruder <simon@sbruder.de>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use actix_web::{error, get, post, web, Responder};
use maud::html;
use sqlx::PgPool;
use uuid::Uuid;
use super::templates::{self, forms, TemplateConfig};
use crate::manage;
use crate::models::*;
pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service(show_item_class)
.service(list_item_classes)
.service(add_item_class)
.service(add_item_class_post)
.service(edit_item_class)
.service(edit_item_class_post);
}
#[get("/item-class/{id}")]
async fn show_item_class(
pool: web::Data<PgPool>,
path: web::Path<Uuid>,
) -> actix_web::Result<impl Responder> {
let id = path.into_inner();
let item_class = manage::item_class::get(&pool, id)
.await
.map_err(error::ErrorInternalServerError)?;
// TODO: Once async closures are stable, use map_or on item_class.parent instead
let parent = match item_class.parent {
Some(id) => manage::item_class::get(&pool, id)
.await
.map(Some)
.map_err(error::ErrorInternalServerError)?,
None => None,
};
let children = manage::item_class::children(&pool, id)
.await
.map_err(error::ErrorInternalServerError)?;
let mut title = item_class.name.clone();
title.push_str(" Item Details");
Ok(templates::base(
TemplateConfig {
path: &format!("/item-class/{}", item_class.id),
title: Some(&title),
page_title: Some(Box::new(item_class.name.clone())),
page_actions: vec![
(templates::helpers::PageAction {
href: &format!("/item-class/{}/edit", item_class.id),
name: "Edit",
}),
],
..Default::default()
},
html! {
table .table {
tr {
th { "UUID" }
td { (item_class.id) }
}
tr {
th { "Name" }
td { (item_class.name) }
}
@if let Some(parent) = parent {
tr {
th { "Parent" }
td { a href={ "/item-class/" (parent.id) } { (parent.name) } }
}
}
}
@if !children.is_empty() {
h3 .mt-4 { "Children" }
ul {
@for child in children {
li {
a href={ "/item-class/" (child.id) } { (child.name) }
}
}
}
}
},
))
}
#[get("/item-classes")]
async fn list_item_classes(pool: web::Data<PgPool>) -> actix_web::Result<impl Responder> {
let item_classes = manage::item_class::get_all_as_map(&pool)
.await
.map_err(error::ErrorInternalServerError)?;
Ok(templates::base(
TemplateConfig {
path: "/item-classes",
title: Some("Item Class List"),
page_title: Some(Box::new("Item Class List")),
page_actions: vec![
(templates::helpers::PageAction {
href: "/item-classes/add",
name: "Add",
}),
],
..Default::default()
},
html! {
table .table {
thead {
tr {
th { "Name" }
th { "Parents" }
}
}
tbody {
@for item_class in item_classes.values() {
tr {
td { a href={ "/item-class/" (item_class.id) } { (item_class.name) } }
td {
@if let Some(parent) = item_class.parent {
@let parent = item_classes.get(&parent).unwrap();
a href={ "/item-class/" (parent.id) } { (parent.name) }
} @else {
"-"
}
}
}
}
}
}
},
))
}
#[get("/item-classes/add")]
async fn add_item_class() -> actix_web::Result<impl Responder> {
Ok(templates::base(
TemplateConfig {
path: "/items-classes/add",
title: Some("Add Item Class"),
page_title: Some(Box::new("Add Item Class")),
..Default::default()
},
html! {
form method="POST" {
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "name",
title: "Name",
required: true,
..Default::default()
})
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "parent",
title: "Parent",
disabled: true,
..Default::default()
})
button .btn.btn-primary type="submit" { "Add" }
}
},
))
}
#[post("/item-classes/add")]
async fn add_item_class_post(
data: web::Form<NewItemClass>,
pool: web::Data<PgPool>,
) -> actix_web::Result<impl Responder> {
let item = manage::item_class::add(&pool, data.into_inner())
.await
.map_err(error::ErrorInternalServerError)?;
Ok(web::Redirect::to("/item-class/".to_owned() + &item.id.to_string()).see_other())
}
#[get("/item-class/{id}/edit")]
async fn edit_item_class(
pool: web::Data<PgPool>,
path: web::Path<Uuid>,
) -> actix_web::Result<impl Responder> {
let id = path.into_inner();
let item_class = manage::item_class::get(&pool, id)
.await
.map_err(error::ErrorInternalServerError)?;
let mut title = item_class.name.clone();
title.push_str(" Item Details");
Ok(templates::base(
TemplateConfig {
path: &format!("/items-class/{}/add", id),
title: Some(&title),
page_title: Some(Box::new(item_class.name.clone())),
..Default::default()
},
html! {
form method="POST" {
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "id",
title: "UUID",
disabled: true,
required: true,
value: Some(item_class.id.to_string().as_str()),
})
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "name",
title: "Name",
required: true,
value: Some(&item_class.name),
..Default::default()
})
(forms::InputGroup {
r#type: forms::InputType::Text,
name: "parent",
title: "Parent",
disabled: item_class.parent.is_none(),
value: item_class.parent.map(|id| id.to_string()).as_deref(),
..Default::default()
})
button .btn.btn-primary type="submit" { "Edit" }
}
},
))
}
#[post("/item-class/{id}/edit")]
async fn edit_item_class_post(
pool: web::Data<PgPool>,
path: web::Path<Uuid>,
data: web::Form<NewItemClass>,
) -> actix_web::Result<impl Responder> {
let id = path.into_inner();
let item_class = manage::item_class::update(&pool, id, data.into_inner())
.await
.map_err(error::ErrorInternalServerError)?;
Ok(web::Redirect::to("/item-class/".to_owned() + &item_class.id.to_string()).see_other())
}