diff --git a/migrations/20250110224901_login.up.sql b/migrations/20250110224901_login.up.sql index b28c0b4..4cfed18 100644 --- a/migrations/20250110224901_login.up.sql +++ b/migrations/20250110224901_login.up.sql @@ -1,7 +1,7 @@ -- Add up migration script here CREATE TABLE IF NOT EXISTS "login" ( user_id BIGSERIAL NOT NULL REFERENCES "user" (user_id), - token VARCHAR(1024) NOT NULL, + authorization_token VARCHAR(1024) NOT NULL, token_creation_time TIMESTAMPTZ NOT NULL DEFAULT NOW (), - PRIMARY KEY (user_id, token) + PRIMARY KEY (user_id, authorization_token) ); diff --git a/src/database/login.rs b/src/database/login.rs index a87e187..3e9d636 100644 --- a/src/database/login.rs +++ b/src/database/login.rs @@ -2,43 +2,43 @@ use crate::feature::login::Login; use super::DATABASE_CONNECTIONS; -pub async fn create(user_id: &i64, token: &String) -> Result { +pub async fn create(user_id: &i64, authorization_token: &String) -> Result { sqlx::query_as!( Login, r#" - INSERT INTO "login"(user_id, token) + INSERT INTO "login"(user_id, authorization_token) VALUES ($1, $2) RETURNING * "#, user_id, - token, + authorization_token, ) .fetch_one(&*DATABASE_CONNECTIONS) .await } -pub async fn read(user_id: &i64, token: &String) -> Result { +pub async fn read(user_id: &i64, authorization_token: &String) -> Result { sqlx::query_as!( Login, r#" - SELECT * FROM "login" WHERE "user_id" = $1 AND "token" = $2 + SELECT * FROM "login" WHERE "user_id" = $1 AND "authorization_token" = $2 "#, user_id, - token + authorization_token ) .fetch_one(&*DATABASE_CONNECTIONS) .await } -pub async fn delete(user_id: &i64, token: &String) -> Result { +pub async fn delete(user_id: &i64, authorization_token: &String) -> Result { sqlx::query_as!( Login, r#" - DELETE FROM "login" WHERE "user_id" = $1 AND "token" = $2 + DELETE FROM "login" WHERE "user_id" = $1 AND "authorization_token" = $2 RETURNING * "#, user_id, - token, + authorization_token, ) .fetch_one(&*DATABASE_CONNECTIONS) .await diff --git a/src/database/user_contact.rs b/src/database/user_contact.rs index 4b09ddd..69c479e 100644 --- a/src/database/user_contact.rs +++ b/src/database/user_contact.rs @@ -67,6 +67,22 @@ pub async fn delete(user_id: &i64, contact_id: &i64) -> Result Result { + sqlx::query_as!( + UserContact, + r#" + SELECT * FROM "user_contact" WHERE "contact_id" = $1 AND "contact_value" = $2 + "#, + contact_id, + contact_value, + ) + .fetch_one(&*DATABASE_CONNECTIONS) + .await +} + pub async fn read_all_for_user(user_id: &i64) -> Result, sqlx::Error> { sqlx::query_as!( UserContact, diff --git a/src/feature/auth.rs b/src/feature/auth.rs index fa71f51..6944013 100644 --- a/src/feature/auth.rs +++ b/src/feature/auth.rs @@ -15,7 +15,7 @@ static ONE_TIME_PASSWORDS: LazyLock>> = #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct OneTimePassword { - pub user_id: i64, + user_id: i64, pub one_time_password: String, } @@ -24,6 +24,13 @@ impl OneTimePassword { RwLock::new(vec![]) } + pub async fn from_string(user: &User, one_time_password: &String) -> Self { + OneTimePassword { + user_id: user.user_id, + one_time_password: one_time_password.to_owned(), + } + } + pub async fn new(user: &User, user_email: &String) -> Result<(), ForumMailError> { let one_time_password = "123".to_owned(); let new_self = Self { diff --git a/src/feature/login.rs b/src/feature/login.rs index 9781a84..656cf2d 100644 --- a/src/feature/login.rs +++ b/src/feature/login.rs @@ -12,23 +12,23 @@ use crate::{database::login, error::ForumAuthError, SERVER_CONFIG}; use super::user::User; -static TOKEN_META: LazyLock = LazyLock::new(TokenMeta::init); +static TOKEN_META: LazyLock = LazyLock::new(AuthorizationTokenMeta::init); #[derive(Debug, Serialize, Deserialize)] pub struct CustomClaim { pub user_id: i64, } -pub struct TokenMeta { - token_key: HS256Key, - token_verification_options: Option, +pub struct AuthorizationTokenMeta { + authorization_token: HS256Key, + authorization_token_verification_options: Option, } -impl TokenMeta { +impl AuthorizationTokenMeta { fn init() -> Self { Self { - token_key: HS256Key::generate(), - token_verification_options: { + authorization_token: HS256Key::generate(), + authorization_token_verification_options: { let mut verification_options = VerificationOptions::default(); verification_options.time_tolerance = Some(jwt_simple::prelude::Duration::from(0)); Some(verification_options) @@ -37,7 +37,7 @@ impl TokenMeta { } async fn create_token(user_id: &i64) -> Option { - let key = &TOKEN_META.token_key; + let key = &TOKEN_META.authorization_token; let custom_claim = CustomClaim { user_id: *user_id }; let claims = Claims::with_custom_claims( custom_claim, @@ -47,23 +47,24 @@ impl TokenMeta { ); let token = key.authenticate(claims).unwrap(); - match TokenMeta::verify_token(&token).await { + match AuthorizationTokenMeta::verify_token(&token).await { Ok(_) => Some(token), Err(_) => None, } } pub async fn verify_token(token: &String) -> Result, jwt_simple::Error> { - TOKEN_META - .token_key - .verify_token::(token, TOKEN_META.token_verification_options.clone()) + TOKEN_META.authorization_token.verify_token::( + token, + TOKEN_META.authorization_token_verification_options.clone(), + ) } } #[derive(Debug, Serialize, Deserialize)] pub struct Login { pub user_id: i64, - pub token: String, + pub authorization_token: String, pub token_creation_time: DateTime, } @@ -71,24 +72,24 @@ impl Login { pub async fn create(user_id: &i64) -> Result { User::read(user_id).await?; - let token = TokenMeta::create_token(user_id) + let token = AuthorizationTokenMeta::create_token(user_id) .await .expect("Should not panic if it isn't configured wrong"); login::create(user_id, &token).await } - pub async fn read(user_id: &i64, token: &String) -> Result { + pub async fn read(user_id: &i64, authorization_token: &String) -> Result { User::read(user_id).await?; - login::read(user_id, token).await + login::read(user_id, authorization_token).await } pub async fn update( user_id: &i64, - token: &String, + authorization_token: &String, ) -> Result> { - let login = Login::read(user_id, token).await?; - match TokenMeta::verify_token(token).await { + let login = Login::read(user_id, authorization_token).await?; + match AuthorizationTokenMeta::verify_token(authorization_token).await { Ok(_) => Ok(login), Err(_) => { if DateTime::::default() @@ -96,7 +97,7 @@ impl Login { .num_minutes() <= SERVER_CONFIG.login_token_refresh_time_limit as i64 { - Login::delete(user_id, token).await?; + Login::delete(user_id, authorization_token).await?; let login = Login::create(user_id).await?; Ok(login) } else { @@ -105,8 +106,8 @@ impl Login { } } } - pub async fn delete(user_id: &i64, token: &String) -> Result { - login::delete(user_id, token).await + pub async fn delete(user_id: &i64, authorization_token: &String) -> Result { + login::delete(user_id, authorization_token).await } pub async fn read_all_for_user(user_id: &i64) -> Result, sqlx::Error> { diff --git a/src/feature/user_contact.rs b/src/feature/user_contact.rs index ca1568d..bc24eb9 100644 --- a/src/feature/user_contact.rs +++ b/src/feature/user_contact.rs @@ -24,6 +24,13 @@ impl UserContact { user_contact::read(&user.user_id, contact_id).await } + pub async fn read_for_value( + contact_id: &i64, + contact_value: &String, + ) -> Result { + user_contact::read_for_value(contact_id, contact_value).await + } + pub async fn update( user: &User, contact_id: &i64, diff --git a/src/routing/admin.rs b/src/routing/admin.rs index cdea02f..b195d25 100644 --- a/src/routing/admin.rs +++ b/src/routing/admin.rs @@ -1,4 +1,6 @@ pub mod contact; +pub mod interaction; +pub mod login; pub mod role; pub mod user; pub mod user_contact; @@ -9,10 +11,12 @@ use super::middleware::builder_or_admin_by_authorization_token; pub fn route() -> Router { Router::new() + .nest("/logins", login::route()) .nest("/users", user::route()) .nest("/roles", role::route()) .nest("/contacts", contact::route()) .nest("/user_contacts", user_contact::route()) + .nest("/interactions", interaction::route()) .route_layer(axum::middleware::from_fn( builder_or_admin_by_authorization_token, )) diff --git a/src/routing/admin/interaction.rs b/src/routing/admin/interaction.rs new file mode 100644 index 0000000..db92e8e --- /dev/null +++ b/src/routing/admin/interaction.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::interaction::Interaction; + +#[derive(Debug, Serialize, Deserialize)] +struct CreateInteraction { + name: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct UpdateInteraction { + 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_interaction): Json) -> impl IntoResponse { + match Interaction::create(&create_interaction.name).await { + Ok(interaction) => (StatusCode::CREATED, Json(serde_json::json!(interaction))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn update(Json(update_interaction): Json) -> impl IntoResponse { + match Interaction::update(&update_interaction.id, &update_interaction.name).await { + Ok(interaction) => (StatusCode::ACCEPTED, Json(serde_json::json!(interaction))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn delete_(Path(id): Path) -> impl IntoResponse { + match Interaction::delete(&id).await { + Ok(interaction) => (StatusCode::NO_CONTENT, Json(serde_json::json!(interaction))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} diff --git a/src/routing/admin/login.rs b/src/routing/admin/login.rs new file mode 100644 index 0000000..315bdf7 --- /dev/null +++ b/src/routing/admin/login.rs @@ -0,0 +1,45 @@ +use std::sync::Arc; + +use axum::{ + http::StatusCode, + response::IntoResponse, + routing::{delete, get}, + Extension, Json, Router, +}; + +use crate::{ + feature::{login::Login, user::User}, + routing::middleware::by_uri_then_insert, +}; + +pub fn route() -> Router { + Router::new() + .route( + "/users/{user_id}", + delete(delete_all_for_user).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) + .route( + "/count/users/{user_id}", + get(count_all_for_user).route_layer(axum::middleware::from_fn(by_uri_then_insert)), + ) +} + +async fn delete_all_for_user(Extension(user): Extension>) -> impl IntoResponse { + match Login::delete_all_for_user(&user.user_id).await { + Ok(logins) => (StatusCode::OK, Json(serde_json::json!(logins))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn count_all_for_user(Extension(user): Extension>) -> impl IntoResponse { + match Login::count_all_for_user(&user.user_id).await { + Ok(login_count) => (StatusCode::OK, Json(serde_json::json!(login_count))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} diff --git a/src/routing/admin/user.rs b/src/routing/admin/user.rs index e4df2b0..91bc758 100644 --- a/src/routing/admin/user.rs +++ b/src/routing/admin/user.rs @@ -90,21 +90,25 @@ async fn update( Extension(target_user): Extension>, Json(update_user): Json, ) -> impl IntoResponse { - match User::update( - &target_user.user_id, - &update_user.name, - &update_user.surname, - &update_user.gender, - &update_user.birth_date, - &update_user.role_id, - ) - .await - { - Ok(user) => (StatusCode::ACCEPTED, Json(serde_json::json!(user))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), + if update_user.role_id == 0 { + (StatusCode::FORBIDDEN, Json(serde_json::json!({}))) + } else { + match User::update( + &target_user.user_id, + &update_user.name, + &update_user.surname, + &update_user.gender, + &update_user.birth_date, + &update_user.role_id, + ) + .await + { + Ok(user) => (StatusCode::ACCEPTED, Json(serde_json::json!(user))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } } } diff --git a/src/routing/interaction.rs b/src/routing/interaction.rs index 63e6b60..4a40bff 100644 --- a/src/routing/interaction.rs +++ b/src/routing/interaction.rs @@ -1,10 +1,4 @@ -use axum::{ - extract::Path, - http::StatusCode, - response::IntoResponse, - routing::{delete, get, patch, post}, - Json, Router, -}; +use axum::{extract::Path, http::StatusCode, response::IntoResponse, routing::get, Json, Router}; use serde::{Deserialize, Serialize}; use crate::feature::interaction::Interaction; @@ -22,23 +16,10 @@ struct UpdateInteraction { 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_interaction): Json) -> impl IntoResponse { - match Interaction::create(&create_interaction.name).await { - Ok(interaction) => (StatusCode::CREATED, Json(serde_json::json!(interaction))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - async fn read(Path(id): Path) -> impl IntoResponse { match Interaction::read(&id).await { Ok(interaction) => (StatusCode::OK, Json(serde_json::json!(interaction))), @@ -49,26 +30,6 @@ async fn read(Path(id): Path) -> impl IntoResponse { } } -async fn update(Json(update_interaction): Json) -> impl IntoResponse { - match Interaction::update(&update_interaction.id, &update_interaction.name).await { - Ok(interaction) => (StatusCode::ACCEPTED, Json(serde_json::json!(interaction))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - -async fn delete_(Path(id): Path) -> impl IntoResponse { - match Interaction::delete(&id).await { - Ok(interaction) => (StatusCode::NO_CONTENT, Json(serde_json::json!(interaction))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - async fn read_all() -> impl IntoResponse { match Interaction::read_all().await { Ok(interactions) => (StatusCode::OK, Json(serde_json::json!(interactions))), diff --git a/src/routing/login.rs b/src/routing/login.rs index 622717f..aff266d 100644 --- a/src/routing/login.rs +++ b/src/routing/login.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use axum::{ - extract::Path, http::StatusCode, response::IntoResponse, routing::{delete, get, patch, post}, @@ -11,18 +10,20 @@ use serde::{Deserialize, Serialize}; use crate::feature::{auth::OneTimePassword, login::Login, user::User, user_contact::UserContact}; -use super::middleware::{user_and_token_then_insert, UserAndAuthorizationToken}; +use super::middleware::{ + by_authorization_token_then_insert, user_and_token_then_insert, UserAndAuthorizationToken, +}; const CONTACT_EMAIL_DEFAULT_ID: i64 = 0; #[derive(Debug, Serialize, Deserialize)] struct CreateOneTimePassword { - pub user_id: i64, + pub user_email: String, } #[derive(Debug, Serialize, Deserialize)] struct CreateLogin { - user_id: i64, + user_email: String, one_time_password: String, } @@ -30,26 +31,48 @@ pub fn route() -> Router { Router::new() .route("/one_time_password", post(create_one_time_password)) .route("/", post(create)) - .route("/users/{user_id}/tokens/{token}", get(read)) + .route( + "/", + get(read).route_layer(axum::middleware::from_fn(user_and_token_then_insert)), + ) .route( "/", 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)) - .route("/users/{user_id}", delete(delete_all_for_user)) - .route("/count/users/{user_id}", get(count_all_for_user)) + .route( + "/", + delete(delete_).route_layer(axum::middleware::from_fn(user_and_token_then_insert)), + ) + .route( + "/users", + delete(delete_all_for_user).route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )), + ) + .route("/count/users", get(count_all_for_user)) } async fn create_one_time_password( Json(create_one_time_password): Json, ) -> 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, &CONTACT_EMAIL_DEFAULT_ID).await { - Ok(user_email) => match OneTimePassword::new(&user, &user_email.contact_value).await { - Ok(_) => (StatusCode::CREATED, Json(serde_json::json!(""))), + match UserContact::read_for_value( + &CONTACT_EMAIL_DEFAULT_ID, + &create_one_time_password.user_email, + ) + .await + { + Ok(user_contact) => match User::read(&user_contact.user_id).await { + Ok(user) => { + match OneTimePassword::new(&user, &create_one_time_password.user_email).await { + Ok(_) => (StatusCode::CREATED, Json(serde_json::json!({}))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } + } Err(err_val) => ( - StatusCode::BAD_REQUEST, + // this must be impossible that's why I send 500 + StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!(err_val.to_string())), ), }, @@ -60,30 +83,50 @@ async fn create_one_time_password( } } async fn create(Json(create_login): Json) -> impl IntoResponse { - let one_time_password = OneTimePassword { - user_id: create_login.user_id, - one_time_password: create_login.one_time_password, - }; + match UserContact::read_for_value(&CONTACT_EMAIL_DEFAULT_ID, &create_login.user_email).await { + Ok(user_contact) => match User::read(&user_contact.user_id).await { + Ok(user) => { + let one_time_password = + OneTimePassword::from_string(&user, &create_login.one_time_password).await; - match OneTimePassword::verify(&one_time_password).await { - true => match Login::create(&one_time_password.user_id).await { - Ok(login) => (StatusCode::CREATED, Json(serde_json::json!(login))), + match OneTimePassword::verify(&one_time_password).await { + true => match Login::create(&user.user_id).await { + Ok(login) => (StatusCode::CREATED, Json(serde_json::json!(login))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + }, + false => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!( + "One Time Password Authentication Failed".to_string() + )), + ), + } + } Err(err_val) => ( - StatusCode::BAD_REQUEST, + // this must be impossible that's why I send 500 + StatusCode::INTERNAL_SERVER_ERROR, Json(serde_json::json!(err_val.to_string())), ), }, - false => ( + Err(err_val) => ( StatusCode::BAD_REQUEST, - Json(serde_json::json!( - "One Time Password Authentication Failed".to_string() - )), + Json(serde_json::json!(err_val.to_string())), ), } } -async fn read(Path((user_id, token)): Path<(i64, String)>) -> impl IntoResponse { - match Login::read(&user_id, &token).await { +async fn read( + Extension(user_and_authorization_token): Extension>, +) -> impl IntoResponse { + match Login::read( + &user_and_authorization_token.user.user_id, + &user_and_authorization_token.authorization_token, + ) + .await + { Ok(login) => (StatusCode::OK, Json(serde_json::json!(login))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -109,8 +152,15 @@ async fn update( } } -async fn delete_(Path((user_id, token)): Path<(i64, String)>) -> impl IntoResponse { - match Login::delete(&user_id, &token).await { +async fn delete_( + Extension(user_and_authorization_token): Extension>, +) -> impl IntoResponse { + match Login::delete( + &user_and_authorization_token.user.user_id, + &user_and_authorization_token.authorization_token, + ) + .await + { Ok(login) => (StatusCode::NO_CONTENT, Json(serde_json::json!(login))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -119,8 +169,8 @@ async fn delete_(Path((user_id, token)): Path<(i64, String)>) -> impl IntoRespon } } -async fn read_all_for_user(Path(user_id): Path) -> impl IntoResponse { - match Login::read_all_for_user(&user_id).await { +async fn delete_all_for_user(Extension(user): Extension>) -> impl IntoResponse { + match Login::delete_all_for_user(&user.user_id).await { Ok(logins) => (StatusCode::OK, Json(serde_json::json!(logins))), Err(err_val) => ( StatusCode::BAD_REQUEST, @@ -129,18 +179,8 @@ async fn read_all_for_user(Path(user_id): Path) -> impl IntoResponse { } } -async fn delete_all_for_user(Path(user_id): Path) -> impl IntoResponse { - match Login::delete_all_for_user(&user_id).await { - Ok(logins) => (StatusCode::OK, Json(serde_json::json!(logins))), - Err(err_val) => ( - StatusCode::BAD_REQUEST, - Json(serde_json::json!(err_val.to_string())), - ), - } -} - -async fn count_all_for_user(Path(user_id): Path) -> impl IntoResponse { - match Login::count_all_for_user(&user_id).await { +async fn count_all_for_user(Extension(user): Extension>) -> impl IntoResponse { + match Login::count_all_for_user(&user.user_id).await { Ok(login_count) => (StatusCode::OK, Json(serde_json::json!(login_count))), Err(err_val) => ( StatusCode::BAD_REQUEST, diff --git a/src/routing/middleware.rs b/src/routing/middleware.rs index 4729807..a4adb16 100644 --- a/src/routing/middleware.rs +++ b/src/routing/middleware.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use crate::{ error::ForumAuthError, - feature::{login::TokenMeta, user::User}, + feature::{login::AuthorizationTokenMeta, user::User}, }; #[derive(Debug, Serialize, Deserialize)] @@ -43,7 +43,7 @@ async fn authorization_token_extraction( async fn user_extraction_from_authorization_token( authorization_token: &String, ) -> Result { - match TokenMeta::verify_token(&authorization_token.to_string()).await { + match AuthorizationTokenMeta::verify_token(&authorization_token.to_string()).await { Ok(claims) => User::read(&claims.custom.user_id) .await .map_err(|err_val| ForumAuthError::AuthenticationFailed(err_val.to_string())), diff --git a/src/routing/user.rs b/src/routing/user.rs index 8c6015d..284d7d2 100644 --- a/src/routing/user.rs +++ b/src/routing/user.rs @@ -1,12 +1,35 @@ -use axum::{extract::Path, http::StatusCode, response::IntoResponse, routing::get, Json, Router}; +use std::sync::Arc; + +use axum::{ + extract::Path, http::StatusCode, response::IntoResponse, routing::get, Extension, Json, Router, +}; use crate::feature::user::User; +use super::middleware::by_authorization_token_then_insert; + pub fn route() -> Router { - Router::new().route("/{user_id}", get(read)) + Router::new() + .route( + "/", + get(read).route_layer(axum::middleware::from_fn( + by_authorization_token_then_insert, + )), + ) + .route("/{user_id}", get(read_anybody)) } -async fn read(Path(user_id): Path) -> impl IntoResponse { +async fn read(Extension(user): Extension>) -> impl IntoResponse { + match User::read(&user.user_id).await { + Ok(user) => (StatusCode::OK, Json(serde_json::json!(user))), + Err(err_val) => ( + StatusCode::BAD_REQUEST, + Json(serde_json::json!(err_val.to_string())), + ), + } +} + +async fn read_anybody(Path(user_id): Path) -> impl IntoResponse { match User::read(&user_id).await { Ok(user) => (StatusCode::OK, Json(serde_json::json!(user))), Err(err_val) => (