todos more traits

This commit is contained in:
2023-09-16 10:28:50 +02:00
parent 2221ee0412
commit 1ffb2c5e74
6 changed files with 114 additions and 64 deletions

View File

@@ -115,7 +115,7 @@ pub mod route {
use crate::AppState;
use axum::{
body::BoxBody,
extract::{Path, State},
extract::{Path, Query, State},
http::HeaderMap,
response::Response,
Extension, Form,
@@ -128,7 +128,9 @@ pub mod route {
#[async_trait]
pub trait Create: super::crud::Create {
type FormX: Send + Sync + 'static;
type Form: Send + Sync + 'static;
type ParentUrlParams: Send + Sync + 'static;
type UrlParams: Send + Sync + 'static;
const URL: &'static str;
@@ -137,8 +139,51 @@ pub mod route {
user: Extension<crate::models::user::User>,
state: State<AppState>,
headers: HeaderMap,
path: Path<Self::UrlParams>,
form: Form<Self::FormX>,
path: Path<(Self::ParentUrlParams, Self::UrlParams)>,
form: Form<Self::Form>,
) -> Result<Response<BoxBody>, crate::Error>;
fn with_prefix(prefix: &'static str) -> String {
format!("{}{}", prefix, Self::URL)
}
}
#[async_trait]
pub trait Read: super::crud::Read {
type UrlParams: Send + Sync + 'static;
type QueryParams: Send + Sync + 'static;
const URL: &'static str;
async fn read(
user: Extension<crate::models::user::User>,
state: State<AppState>,
headers: HeaderMap,
query: Query<Self::QueryParams>,
path: Path<Self::UrlParams>,
) -> Result<Response<BoxBody>, crate::Error>;
fn with_prefix(prefix: &'static str) -> String {
format!("{}{}", prefix, Self::URL)
}
}
#[async_trait]
pub trait Delete: super::crud::Delete {
type ParentUrlParams: Send + Sync + 'static;
type UrlParams: Send + Sync + 'static;
const URL: &'static str;
async fn delete(
user: Extension<crate::models::user::User>,
state: State<AppState>,
headers: HeaderMap,
path: Path<(Self::ParentUrlParams, Self::UrlParams)>,
) -> Result<Response<BoxBody>, crate::Error>;
fn with_prefix(prefix: &'static str) -> String {
format!("{}{}", prefix, Self::URL)
}
}
}

View File

@@ -567,18 +567,19 @@ pub struct TripTodoNew {
#[async_trait]
impl route::Create for Todo {
type FormX = TripTodoNew;
type UrlParams = (Uuid,);
type Form = TripTodoNew;
type ParentUrlParams = (Uuid,);
type UrlParams = ();
const URL: &'static str = "/:id/todo/new";
const URL: &'static str = "/new";
#[tracing::instrument]
async fn create(
Extension(current_user): Extension<crate::models::user::User>,
axum::extract::State(state): axum::extract::State<AppState>,
headers: HeaderMap,
Path((trip_id,)): Path<(Uuid,)>,
Form(form): Form<TripTodoNew>,
Path(((trip_id,), ())): Path<(Self::ParentUrlParams, Self::UrlParams)>,
Form(form): Form<Self::Form>,
) -> Result<Response<BoxBody>, crate::Error> {
let ctx = Context::build(current_user);
// method output is not required as we reload the whole trip todos anyway
@@ -614,6 +615,53 @@ impl route::Create for Todo {
}
}
#[async_trait]
impl route::Delete for Todo {
type ParentUrlParams = (Uuid,);
type UrlParams = (Uuid,);
const URL: &'static str = "/:id/delete";
#[tracing::instrument]
async fn delete(
Extension(current_user): Extension<crate::models::user::User>,
axum::extract::State(state): axum::extract::State<AppState>,
_headers: HeaderMap,
Path(((trip_id,), (todo_id,))): Path<(Self::ParentUrlParams, Self::UrlParams)>,
) -> Result<Response<BoxBody>, crate::Error> {
let ctx = Context::build(current_user);
let deleted = <Self as crud::Delete>::delete(
&ctx,
&state.database_pool,
&TodoFilter { trip_id },
todo_id,
)
.await?;
if !deleted {
return Err(crate::Error::Request(RequestError::NotFound {
message: format!("todo with id {todo_id} not found"),
}));
}
let trip = crate::models::trips::Trip::find(&ctx, &state.database_pool, trip_id).await?;
match trip {
None => Err(crate::Error::Request(RequestError::NotFound {
message: format!("trip with id {trip_id} not found"),
})),
Some(mut trip) => {
trip.load_todos(&ctx, &state.database_pool).await?;
Ok(TodoList {
trip: &trip,
todos: &trip.todos(),
}
.build(None)
.into_response())
}
}
}
}
pub struct NewTodo;
impl NewTodo {

View File

@@ -152,10 +152,17 @@ pub fn router(state: AppState) -> Router {
.route("/:id/todo/:id/edit/save", post(trip_todo_edit_save))
.route("/:id/todo/:id/edit/cancel", post(trip_todo_edit_cancel))
.route(
"/:id/todo/new",
&<crate::models::trips::todos::Todo as route::Create>::with_prefix(
"/:id/todo",
),
post(<crate::models::trips::todos::Todo as route::Create>::create),
)
.route("/:id/todo/:id/delete", post(trip_todo_delete)),
.route(
&<crate::models::trips::todos::Todo as route::Delete>::with_prefix(
"/:id/todo",
),
post(<crate::models::trips::todos::Todo as route::Delete>::delete),
),
)
.nest(
(&TopLevelPage::Inventory.path()).into(),

View File

@@ -1479,42 +1479,3 @@ pub async fn trip_todo_edit_cancel(
.into_response()),
}
}
#[tracing::instrument]
pub async fn trip_todo_delete(
Extension(current_user): Extension<models::user::User>,
State(state): State<AppState>,
headers: HeaderMap,
Path((trip_id, todo_id)): Path<(Uuid, Uuid)>,
) -> Result<impl IntoResponse, Error> {
let ctx = Context::build(current_user);
let deleted = models::trips::todos::Todo::delete(
&ctx,
&state.database_pool,
&TodoFilter { trip_id },
todo_id,
)
.await?;
if !deleted {
return Err(Error::Request(RequestError::NotFound {
message: format!("todo with id {todo_id} not found"),
}));
}
let trip = models::trips::Trip::find(&ctx, &state.database_pool, trip_id).await?;
match trip {
None => Err(Error::Request(RequestError::NotFound {
message: format!("trip with id {trip_id} not found"),
})),
Some(mut trip) => {
trip.load_todos(&ctx, &state.database_pool).await?;
Ok(models::trips::todos::TodoList {
trip: &trip,
todos: &trip.todos(),
}
.build(None)
.into_response())
}
}
}