From bf2b0a439cb4827078c075aee27331c91cc83bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ahmet=20Kaan=20G=C3=9CM=C3=9C=C5=9E?= <96421894+Tahinli@users.noreply.github.com> Date: Sun, 26 Jan 2025 04:39:11 +0300 Subject: [PATCH] feat: :sparkles: admin routing part 2 --- src/feature/user.rs | 88 ++++++++++++-------- src/feature/user_contact.rs | 26 +++--- src/routing.rs | 3 + src/routing/admin.rs | 8 +- src/routing/admin/contact.rs | 58 ++++++++++++++ src/routing/admin/role.rs | 18 +---- src/routing/admin/user.rs | 6 +- src/routing/admin/user_contact.rs | 128 ++++++++++++++++++++++++++++++ src/routing/contact.rs | 53 +------------ src/routing/login.rs | 6 +- src/routing/middleware.rs | 52 +++++++++--- src/routing/user.rs | 9 +-- src/routing/user_contact.rs | 86 ++++++++++++-------- 13 files changed, 370 insertions(+), 171 deletions(-) create mode 100644 src/routing/admin/contact.rs create mode 100644 src/routing/admin/user_contact.rs diff --git a/src/feature/user.rs b/src/feature/user.rs index 0d2fe40..939459f 100644 --- a/src/feature/user.rs +++ b/src/feature/user.rs @@ -124,49 +124,25 @@ impl User { user::count_all_for_gender(gender).await } - pub async fn is_builder(user: &User) -> bool { - if user.role_id == 0 { + async fn is_normal(&self) -> bool { + if self.role_id == 0 { true } else { false } } - pub async fn is_admin(user: &User) -> bool { - if user.role_id == 1 { + async fn is_same_level(&self, target_user: &User) -> bool { + if self.role_id == target_user.role_id { true } else { false } } - pub async fn is_banned(user: &User) -> bool { - if user.role_id == -1 { - true - } else { - false - } - } - - pub async fn is_builder_or_admin(user: &User) -> bool { - if user.role_id == 0 || user.role_id == 1 { - true - } else { - false - } - } - - pub async fn is_self(user: &User, target_user: &User) -> bool { - if user.user_id == target_user.user_id { - true - } else { - false - } - } - - pub async fn is_higher(user: &User, target_user: &User) -> bool { - if user.user_id >= 0 { - if user.user_id < target_user.user_id { + async fn is_higher(&self, target_user: &User) -> bool { + if self.user_id >= 0 { + if self.user_id < target_user.user_id { return true; } } @@ -174,11 +150,55 @@ impl User { false } - pub async fn is_higher_or_self(user: &User, target_user: &User) -> bool { - if User::is_self(user, target_user).await { + pub async fn is_builder(&self) -> bool { + if self.role_id == 0 { true } else { - User::is_higher(user, target_user).await + false + } + } + + pub async fn is_admin(&self) -> bool { + if self.role_id == 1 { + true + } else { + false + } + } + + pub async fn is_banned(&self) -> bool { + if self.role_id == -1 { + true + } else { + false + } + } + + pub async fn is_builder_or_admin(&self) -> bool { + if self.role_id == 0 || self.role_id == 1 { + true + } else { + false + } + } + + pub async fn is_default(&self, target_user: &User) -> bool { + if self.is_banned().await { + false + } else { + if self.is_normal().await { + false + } else { + if self.is_same_level(target_user).await { + true + } else { + if self.is_higher(target_user).await { + true + } else { + false + } + } + } } } } diff --git a/src/feature/user_contact.rs b/src/feature/user_contact.rs index 1b00f2a..ca1568d 100644 --- a/src/feature/user_contact.rs +++ b/src/feature/user_contact.rs @@ -2,6 +2,8 @@ use serde::{Deserialize, Serialize}; use crate::database::user_contact; +use super::user::User; + #[derive(Debug, Serialize, Deserialize)] pub struct UserContact { pub user_id: i64, @@ -11,34 +13,34 @@ pub struct UserContact { impl UserContact { pub async fn create( - user_id: &i64, + user: &User, contact_id: &i64, contact_value: &String, ) -> Result { - user_contact::create(user_id, contact_id, contact_value).await + user_contact::create(&user.user_id, contact_id, contact_value).await } - pub async fn read(user_id: &i64, contact_id: &i64) -> Result { - user_contact::read(user_id, contact_id).await + pub async fn read(user: &User, contact_id: &i64) -> Result { + user_contact::read(&user.user_id, contact_id).await } pub async fn update( - user_id: &i64, + user: &User, contact_id: &i64, contact_value: &String, ) -> Result { - user_contact::update(user_id, contact_id, contact_value).await + user_contact::update(&user.user_id, contact_id, contact_value).await } - pub async fn delete(user_id: &i64, contact_id: &i64) -> Result { - user_contact::delete(user_id, contact_id).await + pub async fn delete(user: &User, contact_id: &i64) -> Result { + user_contact::delete(&user.user_id, contact_id).await } - pub async fn read_all_for_user(user_id: &i64) -> Result, sqlx::Error> { - user_contact::read_all_for_user(user_id).await + pub async fn read_all_for_user(user: &User) -> Result, sqlx::Error> { + user_contact::read_all_for_user(&user.user_id).await } - pub async fn delete_all_for_user(user_id: &i64) -> Result, sqlx::Error> { - user_contact::delete_all_for_user(user_id).await + pub async fn delete_all_for_user(user: &User) -> Result, sqlx::Error> { + user_contact::delete_all_for_user(&user.user_id).await } } diff --git a/src/routing.rs b/src/routing.rs index 18190e5..bd35efd 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -12,6 +12,7 @@ pub mod user; pub mod user_contact; use axum::{http::StatusCode, response::IntoResponse, routing::get, Router}; +use middleware::by_authorization_token; use tower::limit::ConcurrencyLimitLayer; use tower_http::{cors::CorsLayer, trace::TraceLayer}; @@ -31,6 +32,8 @@ pub async fn route(concurrency_limit: &usize) -> Router { .nest("/contacts", contact::route()) .nest("/user_contacts", user_contact::route()) .nest("/admin", admin::route()) + // todo just for beta I think + .route_layer(axum::middleware::from_fn(by_authorization_token)) .layer(CorsLayer::permissive()) .layer(ConcurrencyLimitLayer::new(*concurrency_limit)) .layer(TraceLayer::new_for_http()) diff --git a/src/routing/admin.rs b/src/routing/admin.rs index 060971b..cdea02f 100644 --- a/src/routing/admin.rs +++ b/src/routing/admin.rs @@ -1,15 +1,19 @@ +pub mod contact; pub mod role; pub mod user; +pub mod user_contact; use axum::Router; -use super::middleware::pass_builder_or_admin_by_authorization_token; +use super::middleware::builder_or_admin_by_authorization_token; pub fn route() -> Router { Router::new() .nest("/users", user::route()) .nest("/roles", role::route()) + .nest("/contacts", contact::route()) + .nest("/user_contacts", user_contact::route()) .route_layer(axum::middleware::from_fn( - pass_builder_or_admin_by_authorization_token, + builder_or_admin_by_authorization_token, )) } diff --git a/src/routing/admin/contact.rs b/src/routing/admin/contact.rs new file mode 100644 index 0000000..0557935 --- /dev/null +++ b/src/routing/admin/contact.rs @@ -0,0 +1,58 @@ +use axum::{ + extract::Path, + http::StatusCode, + response::IntoResponse, + routing::{delete, patch, post}, + Json, Router, +}; +use serde::{Deserialize, Serialize}; + +use crate::feature::contact::Contact; + +#[derive(Debug, Serialize, Deserialize)] +struct CreateContact { + name: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct UpdateContact { + id: i64, + name: String, +} + +pub fn route() -> Router { + Router::new() + .route("/", post(create)) + .route("/", patch(update)) + .route("/{id}", delete(delete_)) +} + +async fn create(Json(create_contact): Json) -> impl IntoResponse { + match Contact::create(&create_contact.name).await { + Ok(contact) => (StatusCode::CREATED, Json(serde_json::json!(contact))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn update(Json(update_contact): Json) -> impl IntoResponse { + match Contact::update(&update_contact.id, &update_contact.name).await { + Ok(contact) => (StatusCode::ACCEPTED, Json(serde_json::json!(contact))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn delete_(Path(id): Path) -> impl IntoResponse { + match Contact::delete(&id).await { + Ok(contact) => (StatusCode::NO_CONTENT, Json(serde_json::json!(contact))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} diff --git a/src/routing/admin/role.rs b/src/routing/admin/role.rs index 3576f5b..430aa2c 100644 --- a/src/routing/admin/role.rs +++ b/src/routing/admin/role.rs @@ -2,18 +2,13 @@ use axum::{ extract::Path, http::StatusCode, response::IntoResponse, - routing::{delete, patch, post}, + routing::{delete, patch}, Json, Router, }; use serde::{Deserialize, Serialize}; use crate::feature::role::Role; -#[derive(Debug, Serialize, Deserialize)] -struct CreateRole { - name: String, -} - #[derive(Debug, Serialize, Deserialize)] struct UpdateRole { id: i64, @@ -22,21 +17,10 @@ struct UpdateRole { pub fn route() -> Router { Router::new() - .route("/", post(create)) .route("/", patch(update)) .route("/{id}", delete(delete_)) } -async fn create(Json(create_role): Json) -> impl IntoResponse { - match Role::create(&create_role.name).await { - Ok(role) => (StatusCode::CREATED, Json(serde_json::json!(role))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - async fn update(Json(update_role): Json) -> impl IntoResponse { match Role::update(&update_role.id, &update_role.name).await { Ok(role) => (StatusCode::ACCEPTED, Json(serde_json::json!(role))), diff --git a/src/routing/admin/user.rs b/src/routing/admin/user.rs index 3864c7d..e4df2b0 100644 --- a/src/routing/admin/user.rs +++ b/src/routing/admin/user.rs @@ -10,7 +10,7 @@ use axum::{ use chrono::NaiveDate; use serde::{Deserialize, Serialize}; -use crate::{feature::user::User, routing::middleware::pass_by_uri_user_extraction}; +use crate::{feature::user::User, routing::middleware::by_uri_then_insert}; #[derive(Debug, Serialize, Deserialize)] struct CreateUser { @@ -34,11 +34,11 @@ pub fn route() -> Router { .route("/", post(create)) .route( "/{user_id}", - patch(update).route_layer(axum::middleware::from_fn(pass_by_uri_user_extraction)), + patch(update).route_layer(axum::middleware::from_fn(by_uri_then_insert)), ) .route( "/{user_id}", - delete(delete_).route_layer(axum::middleware::from_fn(pass_by_uri_user_extraction)), + delete(delete_).route_layer(axum::middleware::from_fn(by_uri_then_insert)), ) .route("/", get(read_all)) .route("/names/{name}", get(read_all_for_name)) diff --git a/src/routing/admin/user_contact.rs b/src/routing/admin/user_contact.rs new file mode 100644 index 0000000..f177e66 --- /dev/null +++ b/src/routing/admin/user_contact.rs @@ -0,0 +1,128 @@ +use std::sync::Arc; + +use axum::{ + extract::Path, + http::StatusCode, + response::IntoResponse, + routing::{delete, get, patch, post}, + Extension, Json, Router, +}; +use serde::{Deserialize, Serialize}; + +use crate::{ + feature::{user::User, user_contact::UserContact}, + routing::middleware::by_uri_then_insert, +}; + +#[derive(Debug, Serialize, Deserialize)] +struct CreateUserContact { + pub contact_id: i64, + pub contact_value: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct UpdateUserContact { + pub contact_id: i64, + pub contact_value: String, +} + +pub fn route() -> Router { + Router::new() + .route( + "/users/{user_id}", + post(create).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) + .route( + "/users/{user_id}/contacts/{contact_id}", + get(read).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) + .route( + "/users/{user_id}", + patch(update).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) + .route( + "/users/{user_id}/contacts/{contact_id}", + delete(delete_).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) + .route( + "/users/{user_id}", + delete(delete_all_for_user).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) +} + +async fn create( + Extension(user): Extension>, + Json(create_user_contact): Json, +) -> impl IntoResponse { + match UserContact::create( + &user, + &create_user_contact.contact_id, + &create_user_contact.contact_value, + ) + .await + { + Ok(user_contact) => (StatusCode::CREATED, Json(serde_json::json!(user_contact))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn read( + Extension(user): Extension>, + Path(contact_id): Path, +) -> impl IntoResponse { + match UserContact::read(&user, &contact_id).await { + Ok(user_contact) => (StatusCode::OK, Json(serde_json::json!(user_contact))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn update( + Extension(user): Extension>, + Json(update_user_contact): Json, +) -> impl IntoResponse { + match UserContact::update( + &user, + &update_user_contact.contact_id, + &update_user_contact.contact_value, + ) + .await + { + Ok(user_contact) => (StatusCode::ACCEPTED, Json(serde_json::json!(user_contact))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn delete_( + Extension(user): Extension>, + Path(contact_id): Path, +) -> impl IntoResponse { + match UserContact::delete(&user, &contact_id).await { + Ok(user_contact) => ( + StatusCode::NO_CONTENT, + Json(serde_json::json!(user_contact)), + ), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn delete_all_for_user(Extension(user): Extension>) -> impl IntoResponse { + match UserContact::delete_all_for_user(&user).await { + Ok(user_contacts) => (StatusCode::OK, Json(serde_json::json!(user_contacts))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} diff --git a/src/routing/contact.rs b/src/routing/contact.rs index 32b7fbe..9c696da 100644 --- a/src/routing/contact.rs +++ b/src/routing/contact.rs @@ -1,44 +1,13 @@ -use axum::{ - extract::Path, - http::StatusCode, - response::IntoResponse, - routing::{delete, get, patch, post}, - Json, Router, -}; -use serde::{Deserialize, Serialize}; +use axum::{extract::Path, http::StatusCode, response::IntoResponse, routing::get, Json, Router}; use crate::feature::contact::Contact; -#[derive(Debug, Serialize, Deserialize)] -struct CreateContact { - name: String, -} - -#[derive(Debug, Serialize, Deserialize)] -struct UpdateContact { - id: i64, - name: String, -} - pub fn route() -> Router { Router::new() - .route("/", post(create)) .route("/{id}", get(read)) - .route("/", patch(update)) - .route("/{id}", delete(delete_)) .route("/", get(read_all)) } -async fn create(Json(create_contact): Json) -> impl IntoResponse { - match Contact::create(&create_contact.name).await { - Ok(contact) => (StatusCode::CREATED, Json(serde_json::json!(contact))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - async fn read(Path(id): Path) -> impl IntoResponse { match Contact::read(&id).await { Ok(contact) => (StatusCode::OK, Json(serde_json::json!(contact))), @@ -49,26 +18,6 @@ async fn read(Path(id): Path) -> impl IntoResponse { } } -async fn update(Json(update_contact): Json) -> impl IntoResponse { - match Contact::update(&update_contact.id, &update_contact.name).await { - Ok(contact) => (StatusCode::ACCEPTED, Json(serde_json::json!(contact))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - -async fn delete_(Path(id): Path) -> impl IntoResponse { - match Contact::delete(&id).await { - Ok(contact) => (StatusCode::NO_CONTENT, Json(serde_json::json!(contact))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - async fn read_all() -> impl IntoResponse { match Contact::read_all().await { Ok(contacts) => (StatusCode::OK, Json(serde_json::json!(contacts))), diff --git a/src/routing/login.rs b/src/routing/login.rs index e9a4370..622717f 100644 --- a/src/routing/login.rs +++ b/src/routing/login.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; use crate::feature::{auth::OneTimePassword, login::Login, user::User, user_contact::UserContact}; -use super::middleware::{self, UserAndAuthorizationToken}; +use super::middleware::{user_and_token_then_insert, UserAndAuthorizationToken}; const CONTACT_EMAIL_DEFAULT_ID: i64 = 0; @@ -33,7 +33,7 @@ pub fn route() -> Router { .route("/users/{user_id}/tokens/{token}", get(read)) .route( "/", - patch(update).route_layer(axum::middleware::from_fn(middleware::user_and_token)), + patch(update).route_layer(axum::middleware::from_fn(user_and_token_then_insert)), ) .route("/users/{user_id}/tokens/{token}", delete(delete_)) .route("/users/{user_id}", get(read_all_for_user)) @@ -45,7 +45,7 @@ async fn create_one_time_password( ) -> impl IntoResponse { //todo get user from middleware or something let user = User::read(&create_one_time_password.user_id).await.unwrap(); - match UserContact::read(&user.user_id, &CONTACT_EMAIL_DEFAULT_ID).await { + match UserContact::read(&user, &CONTACT_EMAIL_DEFAULT_ID).await { Ok(user_email) => match OneTimePassword::new(&user, &user_email.contact_value).await { Ok(_) => (StatusCode::CREATED, Json(serde_json::json!(""))), Err(err_val) => ( diff --git a/src/routing/middleware.rs b/src/routing/middleware.rs index 8b31355..4729807 100644 --- a/src/routing/middleware.rs +++ b/src/routing/middleware.rs @@ -86,7 +86,7 @@ async fn user_from_header_and_target_user_from_uri_extraction( Ok(UserAndTargetUser { user, target_user }) } -pub async fn user_and_token( +pub async fn user_and_token_then_insert( mut request: Request, next: Next, ) -> Result { @@ -104,7 +104,17 @@ pub async fn user_and_token( Err(StatusCode::FORBIDDEN) } -pub async fn pass_by_authorization_token( +pub async fn by_authorization_token( + request: Request, + next: Next, +) -> Result { + match user_extraction_from_header(request.headers()).await { + Ok(_) => Ok(next.run(request).await), + Err(_) => Err(StatusCode::FORBIDDEN), + } +} + +pub async fn by_authorization_token_then_insert( mut request: Request, next: Next, ) -> Result { @@ -119,7 +129,7 @@ pub async fn pass_by_authorization_token( } } -pub async fn pass_by_uri_user_extraction( +pub async fn by_uri_then_insert( mut request: Request, next: Next, ) -> Result { @@ -132,7 +142,19 @@ pub async fn pass_by_uri_user_extraction( Err(StatusCode::BAD_REQUEST) } -pub async fn pass_builder_by_authorization_token( +pub async fn builder_by_authorization_token( + request: Request, + next: Next, +) -> Result { + if let Ok(user) = user_extraction_from_header(request.headers()).await { + if User::is_builder(&user).await { + return Ok(next.run(request).await); + } + } + Err(StatusCode::FORBIDDEN) +} + +pub async fn builder_by_authorization_token_then_insert( mut request: Request, next: Next, ) -> Result { @@ -147,7 +169,19 @@ pub async fn pass_builder_by_authorization_token( Err(StatusCode::FORBIDDEN) } -pub async fn pass_builder_or_admin_by_authorization_token( +pub async fn builder_or_admin_by_authorization_token( + request: Request, + next: Next, +) -> Result { + if let Ok(user) = user_extraction_from_header(request.headers()).await { + if User::is_builder_or_admin(&user).await { + return Ok(next.run(request).await); + } + } + Err(StatusCode::FORBIDDEN) +} + +pub async fn builder_or_admin_by_authorization_token_then_insert( mut request: Request, next: Next, ) -> Result { @@ -162,7 +196,7 @@ pub async fn pass_builder_or_admin_by_authorization_token( Err(StatusCode::FORBIDDEN) } -pub async fn pass_builder_by_authorization_token_with_target_user_by_request_uri( +pub async fn builder_by_authorization_token_and_target_user_by_uri_then_insert_target( mut request: Request, next: Next, ) -> Result { @@ -172,7 +206,7 @@ pub async fn pass_builder_by_authorization_token_with_target_user_by_request_uri let user = user_and_target_user.user; let target_user = user_and_target_user.target_user; - if User::is_builder(&user).await { + if user.is_builder().await && user.is_default(&target_user).await { let target_user = Arc::new(target_user); request.extensions_mut().insert(target_user); @@ -182,7 +216,7 @@ pub async fn pass_builder_by_authorization_token_with_target_user_by_request_uri Err(StatusCode::FORBIDDEN) } -pub async fn pass_builder_or_admin_by_authorization_token_with_target_user_by_request_uri( +pub async fn builder_or_admin_by_authorization_token_and_target_user_by_uri_then_insert_target( mut request: Request, next: Next, ) -> Result { @@ -192,7 +226,7 @@ pub async fn pass_builder_or_admin_by_authorization_token_with_target_user_by_re let user = user_and_target_user.user; let target_user = user_and_target_user.target_user; - if User::is_builder_or_admin(&user).await { + if user.is_default(&target_user).await { let target_user = Arc::new(target_user); request.extensions_mut().insert(target_user); diff --git a/src/routing/user.rs b/src/routing/user.rs index cd0d1fe..8c6015d 100644 --- a/src/routing/user.rs +++ b/src/routing/user.rs @@ -2,15 +2,8 @@ use axum::{extract::Path, http::StatusCode, response::IntoResponse, routing::get use crate::feature::user::User; -use super::middleware; - pub fn route() -> Router { - Router::new() - .route("/{user_id}", get(read)) - // todo just for beta I think - .route_layer(axum::middleware::from_fn( - middleware::pass_by_authorization_token, - )) + Router::new().route("/{user_id}", get(read)) } async fn read(Path(user_id): Path) -> impl IntoResponse { diff --git a/src/routing/user_contact.rs b/src/routing/user_contact.rs index 046aef6..22cac3d 100644 --- a/src/routing/user_contact.rs +++ b/src/routing/user_contact.rs @@ -1,41 +1,66 @@ +use std::sync::Arc; + use axum::{ extract::Path, http::StatusCode, response::IntoResponse, routing::{delete, get, patch, post}, - Json, Router, + Extension, Json, Router, }; use serde::{Deserialize, Serialize}; -use crate::feature::user_contact::UserContact; +use crate::feature::{user::User, user_contact::UserContact}; + +use super::middleware::{by_authorization_token_then_insert, by_uri_then_insert}; #[derive(Debug, Serialize, Deserialize)] struct CreateUserContact { - pub user_id: i64, pub contact_id: i64, pub contact_value: String, } #[derive(Debug, Serialize, Deserialize)] struct UpdateUserContact { - pub user_id: i64, pub contact_id: i64, pub contact_value: String, } pub fn route() -> Router { Router::new() - .route("/", post(create)) - .route("/roles/{user_id}/contacts/{contact_id}", get(read)) - .route("/", patch(update)) - .route("/roles/{user_id}/contacts/{contact_id}", delete(delete_)) - .route("/users/{user_id}", get(read_all_for_user)) - .route("/users/{user_id}", delete(delete_all_for_user)) + .route( + "/", + post(create).route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )), + ) + .route( + "/users/{user_id}/contacts/{contact_id}", + get(read).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) + .route( + "/", + patch(update).route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )), + ) + .route( + "/users/contacts/{contact_id}", + delete(delete_).route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )), + ) + .route( + "/users/{user_id}", + get(read_all_for_user).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) } -async fn create(Json(create_user_contact): Json) -> impl IntoResponse { +async fn create( + Extension(user): Extension>, + Json(create_user_contact): Json, +) -> impl IntoResponse { match UserContact::create( - &create_user_contact.user_id, + &user, &create_user_contact.contact_id, &create_user_contact.contact_value, ) @@ -49,8 +74,11 @@ async fn create(Json(create_user_contact): Json) -> impl Into } } -async fn read(Path((user_id, contact_id)): Path<(i64, i64)>) -> impl IntoResponse { - match UserContact::read(&user_id, &contact_id).await { +async fn read( + Extension(user): Extension>, + Path(contact_id): Path, +) -> impl IntoResponse { + match UserContact::read(&user, &contact_id).await { Ok(user_contact) => (StatusCode::OK, Json(serde_json::json!(user_contact))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -59,9 +87,12 @@ async fn read(Path((user_id, contact_id)): Path<(i64, i64)>) -> impl IntoRespons } } -async fn update(Json(update_user_contact): Json) -> impl IntoResponse { +async fn update( + Extension(user): Extension>, + Json(update_user_contact): Json, +) -> impl IntoResponse { match UserContact::update( - &update_user_contact.user_id, + &user, &update_user_contact.contact_id, &update_user_contact.contact_value, ) @@ -75,8 +106,11 @@ async fn update(Json(update_user_contact): Json) -> impl Into } } -async fn delete_(Path((user_id, contact_id)): Path<(i64, i64)>) -> impl IntoResponse { - match UserContact::delete(&user_id, &contact_id).await { +async fn delete_( + Extension(user): Extension>, + Path(contact_id): Path, +) -> impl IntoResponse { + match UserContact::delete(&user, &contact_id).await { Ok(user_contact) => ( StatusCode::NO_CONTENT, Json(serde_json::json!(user_contact)), @@ -88,19 +122,9 @@ async fn delete_(Path((user_id, contact_id)): Path<(i64, i64)>) -> impl IntoResp } } -async fn read_all_for_user(Path(user_id): Path) -> impl IntoResponse { - match UserContact::read_all_for_user(&user_id).await { - Ok(role_contacts) => (StatusCode::OK, Json(serde_json::json!(role_contacts))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - -async fn delete_all_for_user(Path(user_id): Path) -> impl IntoResponse { - match UserContact::delete_all_for_user(&user_id).await { - Ok(role_contacts) => (StatusCode::OK, Json(serde_json::json!(role_contacts))), +async fn read_all_for_user(Extension(user): Extension>) -> impl IntoResponse { + match UserContact::read_all_for_user(&user).await { + Ok(user_contacts) => (StatusCode::OK, Json(serde_json::json!(user_contacts))), Err(err_val) => ( StatusCode::BAD_REQUEST, Json(serde_json::json!(err_val.to_string())),