From 8c0a4c53b8313f4188dd10e8c5c4017cad531d50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20K=C3=B6rber?= Date: Sun, 17 Sep 2023 15:45:02 +0200 Subject: [PATCH] works, lets do updates now --- Cargo.lock | 13 +++++++ Cargo.toml | 2 +- src/components/mod.rs | 64 +++++++++++++++++++++---------- src/components/trips/todos/mod.rs | 44 +++++++++++++-------- src/routing/mod.rs | 18 +++------ src/routing/routes.rs | 10 ++--- 6 files changed, 97 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 141b3b6..955144f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,6 +132,7 @@ checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", "axum-core", + "axum-macros", "bitflags 1.3.2", "bytes", "futures-util", @@ -174,6 +175,18 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-macros" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.35", +] + [[package]] name = "axum-prometheus" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index f71f18d..c5035fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ features = ["derive"] [dependencies.axum] version = "0.6" -features = ["headers"] +features = ["headers", "macros"] [dependencies.tokio] version = "1" diff --git a/src/components/mod.rs b/src/components/mod.rs index 0e97efe..d726b1e 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -7,9 +7,9 @@ pub mod crud { #[async_trait] pub trait Create: Sized { - type Id; - type Filter; - type Info; + type Id: Sized + Send + Sync + 'static; + type Filter: Sized + Send + Sync + 'static; + type Info: Sized + Send + Sync + 'static; async fn create( ctx: &Context, @@ -42,14 +42,14 @@ pub mod crud { pub trait Update: Sized { type Id; type Filter; - type Update; + type UpdateElement; async fn update( ctx: &Context, pool: &sqlite::Pool, filter: Self::Filter, id: Self::Id, - update: Self::Update, + update: Self::UpdateElement, ) -> Result, Error>; } @@ -116,7 +116,7 @@ pub mod route { use crate::AppState; use axum::{ - body::BoxBody, + body::{BoxBody, HttpBody}, extract::{Path, Query, State}, http::HeaderMap, response::Response, @@ -132,7 +132,6 @@ pub mod route { pub trait Create: super::crud::Create { type Form: Send + Sync + 'static; - type ParentUrlParams: Send + Sync + 'static; type UrlParams: Send + Sync + 'static; const URL: &'static str; @@ -141,13 +140,9 @@ pub mod route { user: Extension, state: State, headers: HeaderMap, - path: Path<(Self::ParentUrlParams, Self::UrlParams)>, + path: Path, form: Form, ) -> Result, crate::Error>; - - fn with_prefix(prefix: &'static str) -> String { - format!("{}{}", prefix, Self::URL) - } } #[async_trait] @@ -164,15 +159,40 @@ pub mod route { query: Query, path: Path, ) -> Result, crate::Error>; + } - fn with_prefix(prefix: &'static str) -> String { - format!("{}{}", prefix, Self::URL) - } + #[async_trait] + pub trait Update: super::crud::Update { + type UrlParams: Send + Sync + 'static; + type UpdateForm: Send + Sync + 'static; + + const URL: &'static str; + + async fn start( + user: Extension, + state: State, + headers: HeaderMap, + path: Path, + ) -> Result, crate::Error>; + + async fn save( + user: Extension, + state: State, + headers: HeaderMap, + path: Path, + form: Form, + ) -> Result, crate::Error>; + + async fn cancel( + user: Extension, + state: State, + headers: HeaderMap, + path: Path, + ) -> Result, crate::Error>; } #[async_trait] pub trait Delete: super::crud::Delete { - type ParentUrlParams: Send + Sync + 'static; type UrlParams: Send + Sync + 'static; const URL: &'static str; @@ -181,11 +201,15 @@ pub mod route { user: Extension, state: State, headers: HeaderMap, - path: Path<(Self::ParentUrlParams, Self::UrlParams)>, + path: Path, ) -> Result, crate::Error>; + } - fn with_prefix(prefix: &'static str) -> String { - format!("{}{}", prefix, Self::URL) - } + pub trait Router: Create + Delete { + fn get() -> axum::Router + where + B: HttpBody + Send + 'static, + ::Data: Send, + ::Error: std::error::Error + Sync + Send; } } diff --git a/src/components/trips/todos/mod.rs b/src/components/trips/todos/mod.rs index 4c359b9..8c48406 100644 --- a/src/components/trips/todos/mod.rs +++ b/src/components/trips/todos/mod.rs @@ -2,7 +2,7 @@ pub mod list; pub use list::List; use axum::{ - body::BoxBody, + body::{BoxBody, HttpBody}, extract::{Form, Path}, http::HeaderMap, response::{IntoResponse, Redirect, Response}, @@ -215,7 +215,7 @@ impl crud::Create for Todo { } #[derive(Debug)] -pub enum Update { +pub enum UpdateElement { State(State), Description(String), } @@ -224,7 +224,7 @@ pub enum Update { impl crud::Update for Todo { type Id = Uuid; type Filter = Filter; - type Update = Update; + type UpdateElement = UpdateElement; #[tracing::instrument] async fn update( @@ -232,13 +232,13 @@ impl crud::Update for Todo { pool: &sqlite::Pool, filter: Self::Filter, id: Self::Id, - update: Self::Update, + update_element: Self::UpdateElement, ) -> Result, Error> { let user_id = ctx.user.id.to_string(); let trip_id_param = filter.trip_id.to_string(); let todo_id_param = id.to_string(); - match update { - Update::State(state) => { + match update_element { + UpdateElement::State(state) => { let done = state == State::Done; let result = crate::query_one!( @@ -270,7 +270,7 @@ impl crud::Update for Todo { Ok(result) } - Update::Description(new_description) => { + UpdateElement::Description(new_description) => { let user_id = ctx.user.id.to_string(); let trip_id_param = filter.trip_id.to_string(); let todo_id_param = id.to_string(); @@ -566,17 +566,16 @@ pub struct TripTodoNew { #[async_trait] impl route::Create for Todo { type Form = TripTodoNew; - type ParentUrlParams = (Uuid,); - type UrlParams = (); + type UrlParams = (Uuid,); - const URL: &'static str = "/new"; + const URL: &'static str = "/:id/todo/new"; #[tracing::instrument] async fn create( Extension(current_user): Extension, axum::extract::State(state): axum::extract::State, headers: HeaderMap, - Path(((trip_id,), ())): Path<(Self::ParentUrlParams, Self::UrlParams)>, + Path((trip_id,)): Path, Form(form): Form, ) -> Result, crate::Error> { let ctx = Context::build(current_user); @@ -615,17 +614,16 @@ impl route::Create for Todo { #[async_trait] impl route::Delete for Todo { - type ParentUrlParams = (Uuid,); - type UrlParams = (Uuid,); + type UrlParams = (Uuid, Uuid); - const URL: &'static str = "/:id/delete"; + const URL: &'static str = "/:id/todo/:id/delete"; #[tracing::instrument] async fn delete( Extension(current_user): Extension, axum::extract::State(state): axum::extract::State, _headers: HeaderMap, - Path(((trip_id,), (todo_id,))): Path<(Self::ParentUrlParams, Self::UrlParams)>, + Path((trip_id, todo_id)): Path, ) -> Result, crate::Error> { let ctx = Context::build(current_user); let deleted = ::delete( @@ -659,3 +657,19 @@ impl route::Delete for Todo { } } } + +impl route::Router for Todo { + fn get() -> axum::Router + where + B: HttpBody + Send + 'static, + ::Data: Send, + ::Error: std::error::Error + Sync + Send, + { + axum::Router::new() + .route("/new", axum::routing::post(::create)) + .route( + "/:id/delete", + axum::routing::post(::delete), + ) + } +} diff --git a/src/routing/mod.rs b/src/routing/mod.rs index 812ff3c..ffccdc0 100644 --- a/src/routing/mod.rs +++ b/src/routing/mod.rs @@ -12,7 +12,10 @@ use uuid::Uuid; use std::{fmt, time::Duration}; use tower::{timeout::TimeoutLayer, ServiceBuilder}; -use crate::{components::route, AppState, Error, RequestError, TopLevelPage}; +use crate::{ + components::{self, route::Router as _}, + AppState, Error, RequestError, TopLevelPage, +}; use super::auth; @@ -151,18 +154,7 @@ pub fn router(state: AppState) -> Router { .route("/:id/todo/:id/edit", post(trip_todo_edit)) .route("/:id/todo/:id/edit/save", post(trip_todo_edit_save)) .route("/:id/todo/:id/edit/cancel", post(trip_todo_edit_cancel)) - .route( - &::with_prefix( - "/:id/todo", - ), - post(::create), - ) - .route( - &::with_prefix( - "/:id/todo", - ), - post(::delete), - ), + .nest("/:id/todo/", components::trips::todos::Todo::get()), ) .nest( (&TopLevelPage::Inventory.path()).into(), diff --git a/src/routing/routes.rs b/src/routing/routes.rs index d5cb33d..3ac977a 100644 --- a/src/routing/routes.rs +++ b/src/routing/routes.rs @@ -1281,7 +1281,7 @@ pub async fn trip_todo_done_htmx( &state.database_pool, todos::Filter { trip_id }, todo_id, - todos::Update::State(components::trips::todos::State::Done), + todos::UpdateElement::State(components::trips::todos::State::Done), ) .await?; @@ -1317,7 +1317,7 @@ pub async fn trip_todo_done( &state.database_pool, todos::Filter { trip_id }, todo_id, - todos::Update::State(components::trips::todos::State::Done), + todos::UpdateElement::State(components::trips::todos::State::Done), ) .await?; @@ -1336,7 +1336,7 @@ pub async fn trip_todo_undone_htmx( &state.database_pool, todos::Filter { trip_id }, todo_id, - todos::Update::State(components::trips::todos::State::Todo), + todos::UpdateElement::State(components::trips::todos::State::Todo), ) .await?; @@ -1372,7 +1372,7 @@ pub async fn trip_todo_undone( &state.database_pool, todos::Filter { trip_id }, todo_id, - todos::Update::State(components::trips::todos::State::Todo), + todos::UpdateElement::State(components::trips::todos::State::Todo), ) .await?; @@ -1429,7 +1429,7 @@ pub async fn trip_todo_edit_save( &state.database_pool, todos::Filter { trip_id }, todo_id, - todos::Update::Description(form.description), + todos::UpdateElement::Description(form.description), ) .await?;