From 8d4a981055ebf52058ce3fb8cdbe9bb910b8b6d7 Mon Sep 17 00:00:00 2001 From: Max Hohlfeld Date: Tue, 20 May 2025 20:55:36 +0200 Subject: [PATCH] feat: WIP clothing edit and delete --- web/src/endpoints/clothing/delete.rs | 27 ++++++++++++ web/src/endpoints/clothing/get_edit.rs | 30 +++++++++++++ web/src/endpoints/clothing/get_new.rs | 21 +++++++++ web/src/endpoints/clothing/get_read.rs | 27 ++++++++++++ web/src/endpoints/clothing/mod.rs | 30 +++++++++++++ web/src/endpoints/clothing/post_edit.rs | 35 +++++++++++++++ web/src/endpoints/clothing/post_new.rs | 25 +++++++++++ web/src/endpoints/mod.rs | 8 ++++ web/src/models/clothing.rs | 13 ++++-- .../clothing/clothing_entry_edit.html | 44 +++++++++++++------ .../clothing/clothing_entry_read.html | 32 +++++++++----- web/templates/clothing/overview.html | 3 ++ 12 files changed, 266 insertions(+), 29 deletions(-) create mode 100644 web/src/endpoints/clothing/delete.rs create mode 100644 web/src/endpoints/clothing/get_edit.rs create mode 100644 web/src/endpoints/clothing/get_new.rs create mode 100644 web/src/endpoints/clothing/get_read.rs create mode 100644 web/src/endpoints/clothing/post_edit.rs create mode 100644 web/src/endpoints/clothing/post_new.rs diff --git a/web/src/endpoints/clothing/delete.rs b/web/src/endpoints/clothing/delete.rs new file mode 100644 index 00000000..c1c406b8 --- /dev/null +++ b/web/src/endpoints/clothing/delete.rs @@ -0,0 +1,27 @@ +use actix_web::{web, HttpResponse, Responder}; +use sqlx::PgPool; + +use crate::{ + endpoints::IdPath, + models::{Clothing, Role, User}, + utils::ApplicationError, +}; + +#[actix_web::delete("/clothing/{id}")] +pub async fn delete( + user: web::ReqData, + pool: web::Data, + path: web::Path, +) -> Result { + if user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); + } + + let Some(clothing) = Clothing::read(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + Clothing::delete(pool.get_ref(), clothing.id).await?; + + Ok(HttpResponse::Ok().finish()) +} diff --git a/web/src/endpoints/clothing/get_edit.rs b/web/src/endpoints/clothing/get_edit.rs new file mode 100644 index 00000000..5e141e00 --- /dev/null +++ b/web/src/endpoints/clothing/get_edit.rs @@ -0,0 +1,30 @@ +use actix_web::{web, HttpResponse, Responder}; +use sqlx::PgPool; + +use crate::{ + endpoints::{clothing::EditClothingPartialTemplate, IdPath}, + models::{Clothing, Role, User}, + utils::{ApplicationError, TemplateResponse}, +}; + +#[actix_web::get("/clothing/edit/{id}")] +pub async fn get( + user: web::ReqData, + pool: web::Data, + path: web::Path, +) -> Result { + if user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); + } + + let Some(clothing) = Clothing::read(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + let template = EditClothingPartialTemplate { + id: Some(clothing.id), + name: Some(clothing.name), + }; + + Ok(template.to_response()?) +} diff --git a/web/src/endpoints/clothing/get_new.rs b/web/src/endpoints/clothing/get_new.rs new file mode 100644 index 00000000..302e7890 --- /dev/null +++ b/web/src/endpoints/clothing/get_new.rs @@ -0,0 +1,21 @@ +use actix_web::{web, Responder}; + +use crate::{ + endpoints::clothing::EditClothingPartialTemplate, + models::{Role, User}, + utils::{ApplicationError, TemplateResponse}, +}; + +#[actix_web::get("/clothing/new")] +pub async fn get(user: web::ReqData) -> Result { + if user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); + } + + let template = EditClothingPartialTemplate { + id: None, + name: None, + }; + + Ok(template.to_response()?) +} diff --git a/web/src/endpoints/clothing/get_read.rs b/web/src/endpoints/clothing/get_read.rs new file mode 100644 index 00000000..def1e169 --- /dev/null +++ b/web/src/endpoints/clothing/get_read.rs @@ -0,0 +1,27 @@ +use actix_web::{web, HttpResponse, Responder}; +use sqlx::PgPool; + +use crate::{ + endpoints::{clothing::ReadClothingPartialTemplate, IdPath}, + models::{Clothing, Role, User}, + utils::{ApplicationError, TemplateResponse}, +}; + +#[actix_web::get("/clothing/{id}")] +pub async fn get( + user: web::ReqData, + pool: web::Data, + path: web::Path, +) -> Result { + if user.role != Role::Admin { + return Err(ApplicationError::Unauthorized); + } + + let Some(clothing) = Clothing::read(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + let template = ReadClothingPartialTemplate { c: clothing }; + + Ok(template.to_response()?) +} diff --git a/web/src/endpoints/clothing/mod.rs b/web/src/endpoints/clothing/mod.rs index c85fc4b5..f542f0f5 100644 --- a/web/src/endpoints/clothing/mod.rs +++ b/web/src/endpoints/clothing/mod.rs @@ -1 +1,31 @@ +use askama::Template; +use serde::Deserialize; + +use crate::models::Clothing; +use crate::filters; + +pub mod delete; +pub mod get_edit; +pub mod get_new; pub mod get_overview; +pub mod get_read; +pub mod post_edit; +pub mod post_new; + +#[derive(Template)] +#[template(path = "clothing/clothing_entry_edit.html")] +struct EditClothingPartialTemplate { + id: Option, + name: Option, +} + +#[derive(Template)] +#[template(path = "clothing/clothing_entry_read.html")] +struct ReadClothingPartialTemplate { + c: Clothing, +} + +#[derive(Deserialize)] +struct NewOrEditClothingForm { + name: String, +} diff --git a/web/src/endpoints/clothing/post_edit.rs b/web/src/endpoints/clothing/post_edit.rs new file mode 100644 index 00000000..b883e7bf --- /dev/null +++ b/web/src/endpoints/clothing/post_edit.rs @@ -0,0 +1,35 @@ +use actix_web::{web, HttpResponse, Responder}; +use sqlx::PgPool; + +use crate::{ + endpoints::{ + clothing::{NewOrEditClothingForm, ReadClothingPartialTemplate}, + IdPath, + }, + models::{Clothing, Role, User}, + utils::{ApplicationError, TemplateResponse}, +}; + +#[actix_web::post("/clothing/{id}")] +pub async fn post( + user: web::ReqData, + pool: web::Data, + path: web::Path, + form: web::Form, +) -> Result { + if user.role == Role::Admin { + return Err(ApplicationError::Unauthorized); + } + + let Some(mut clothing) = Clothing::read(pool.get_ref(), path.id).await? else { + return Ok(HttpResponse::NotFound().finish()); + }; + + clothing.name = form.name.to_string(); + + Clothing::update(pool.get_ref(), clothing.id, &clothing.name).await?; + + let template = ReadClothingPartialTemplate { c: clothing }; + + Ok(template.to_response()?) +} diff --git a/web/src/endpoints/clothing/post_new.rs b/web/src/endpoints/clothing/post_new.rs new file mode 100644 index 00000000..3b88a203 --- /dev/null +++ b/web/src/endpoints/clothing/post_new.rs @@ -0,0 +1,25 @@ +use actix_web::{web, Responder}; +use sqlx::PgPool; + +use crate::{ + endpoints::clothing::{NewOrEditClothingForm, ReadClothingPartialTemplate}, + models::{Clothing, Role, User}, + utils::{ApplicationError, TemplateResponse}, +}; + +#[actix_web::post("/clothing")] +pub async fn post( + user: web::ReqData, + pool: web::Data, + form: web::Form, +) -> Result { + if user.role == Role::Admin { + return Err(ApplicationError::Unauthorized); + } + + let clothing = Clothing::create(pool.get_ref(), &form.name).await?; + + let template = ReadClothingPartialTemplate { c: clothing }; + + Ok(template.to_response()?) +} diff --git a/web/src/endpoints/mod.rs b/web/src/endpoints/mod.rs index 06128d35..d7b29668 100644 --- a/web/src/endpoints/mod.rs +++ b/web/src/endpoints/mod.rs @@ -93,4 +93,12 @@ pub fn init(cfg: &mut ServiceConfig) { cfg.service(vehicle_assignment::post_new::post); cfg.service(vehicle_assignment::delete::delete); + + cfg.service(clothing::get_overview::get); + cfg.service(clothing::get_edit::get); + cfg.service(clothing::get_new::get); + cfg.service(clothing::get_read::get); + cfg.service(clothing::delete::delete); + cfg.service(clothing::post_new::post); + cfg.service(clothing::post_edit::post); } diff --git a/web/src/models/clothing.rs b/web/src/models/clothing.rs index cc29e042..eea98ddf 100644 --- a/web/src/models/clothing.rs +++ b/web/src/models/clothing.rs @@ -9,12 +9,17 @@ pub struct Clothing { } impl Clothing { - pub async fn create(pool: &PgPool, name: &str) -> Result<()> { - query!("INSERT INTO clothing (name) VALUES ($1);", name) - .execute(pool) + pub async fn create(pool: &PgPool, name: &str) -> Result { + let r = query!("INSERT INTO clothing (name) VALUES ($1) RETURNING id;", name) + .fetch_one(pool) .await?; - Ok(()) + let created_clothing = Clothing { + id: r.id, + name: name.to_string() + }; + + Ok(created_clothing) } pub async fn read_all(pool: &PgPool) -> Result> { diff --git a/web/templates/clothing/clothing_entry_edit.html b/web/templates/clothing/clothing_entry_edit.html index a5dcfad6..3f7c64a7 100644 --- a/web/templates/clothing/clothing_entry_edit.html +++ b/web/templates/clothing/clothing_entry_edit.html @@ -1,15 +1,33 @@
  • - -
    - - -
    +
    +
    +
    +
    + +
    + +
    + + {% if let Some(id) = id %} + + {% else %} + + {% endif %} +
    +
    +
    +
  • diff --git a/web/templates/clothing/clothing_entry_read.html b/web/templates/clothing/clothing_entry_read.html index 0055c9b3..6e4b11d0 100644 --- a/web/templates/clothing/clothing_entry_read.html +++ b/web/templates/clothing/clothing_entry_read.html @@ -1,15 +1,23 @@
  • - {{ c.name }}" -
    - - +
    +
    +
    + {{ c.name }} +
    + +
    + + +
    +
  • diff --git a/web/templates/clothing/overview.html b/web/templates/clothing/overview.html index 247f9b07..96a8f81d 100644 --- a/web/templates/clothing/overview.html +++ b/web/templates/clothing/overview.html @@ -13,6 +13,9 @@ {% for c in clothings %} {% include "clothing_entry_read.html" %} {% endfor %} +
  • + +