todos more traits
This commit is contained in:
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -132,7 +132,6 @@ checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"axum-macros",
|
||||
"bitflags 1.3.2",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
@@ -175,18 +174,6 @@ 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"
|
||||
|
||||
@@ -18,6 +18,8 @@ default = ["jaeger", "prometheus", "tokio-console"]
|
||||
opt-level = 0
|
||||
lto = "off"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dependencies.async-trait]
|
||||
version = "0.1"
|
||||
|
||||
@@ -49,7 +51,7 @@ features = ["derive"]
|
||||
|
||||
[dependencies.axum]
|
||||
version = "0.6"
|
||||
features = ["headers", "macros"]
|
||||
features = ["headers"]
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user