feat: add user management API with endpoint to retrieve current user information
This commit is contained in:
@@ -2,6 +2,7 @@ pub mod tag {
|
||||
/// Health tag constant
|
||||
pub const HEALTH_TAG: &str = "Health";
|
||||
pub const AUTH_TAG: &str = "Authentication";
|
||||
pub const USER_TAG: &str = "User";
|
||||
}
|
||||
|
||||
#[derive(utoipa::OpenApi)]
|
||||
@@ -11,16 +12,21 @@ pub mod tag {
|
||||
// Authentication paths
|
||||
crate::routes::api::auth::login::login,
|
||||
crate::routes::api::auth::init_admin::init_admin,
|
||||
// User management paths
|
||||
crate::routes::api::restricted::user::me::get_user_info,
|
||||
),
|
||||
components(
|
||||
schemas(crate::routes::api::health::info::HealthInfo),
|
||||
// Authentication schemas
|
||||
schemas(crate::routes::api::auth::login::LoginRequest),
|
||||
schemas(crate::routes::api::auth::init_admin::AdminInitRequest),
|
||||
// User management schemas
|
||||
schemas(crate::routes::api::restricted::user::me::UserInfo),
|
||||
),
|
||||
tags(
|
||||
(name = tag::HEALTH_TAG, description = "Health information API"),
|
||||
(name = tag::AUTH_TAG, description = "Authentication API")
|
||||
(name = tag::AUTH_TAG, description = "Authentication API"),
|
||||
(name = tag::USER_TAG, description = "User management API")
|
||||
)
|
||||
)]
|
||||
pub struct ApiDoc;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
pub mod user;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::Router;
|
||||
@@ -6,8 +8,7 @@ use crate::{middlewares::require_auth::require_auth, routes::AppState};
|
||||
|
||||
pub fn get_restricted_router(state: Arc<AppState>) -> Router {
|
||||
Router::new()
|
||||
//
|
||||
//
|
||||
.nest("/user", user::get_user_router(state.clone()))
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_auth,
|
||||
|
||||
13
apps/api/src/routes/api/restricted/user.rs
Normal file
13
apps/api/src/routes/api/restricted/user.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
pub mod me;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::Router;
|
||||
|
||||
use crate::routes::AppState;
|
||||
|
||||
pub fn get_user_router(state: Arc<AppState>) -> Router {
|
||||
Router::new()
|
||||
.route("/me", axum::routing::get(me::get_user_info))
|
||||
.with_state(state)
|
||||
}
|
||||
64
apps/api/src/routes/api/restricted/user/me.rs
Normal file
64
apps/api/src/routes/api/restricted/user/me.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use axum::{
|
||||
Extension, Json,
|
||||
extract::State,
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tracing::error;
|
||||
|
||||
use crate::{
|
||||
middlewares::request_info::RequestInfo,
|
||||
routes::{AppState, api::openapi::tag::USER_TAG},
|
||||
};
|
||||
|
||||
/// System health information
|
||||
#[derive(Serialize, Deserialize, utoipa::ToSchema)]
|
||||
pub struct UserInfo {
|
||||
/// User ID
|
||||
pub id: uuid::Uuid,
|
||||
/// Username
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
/// Get current user information
|
||||
///
|
||||
/// Returns the information of the currently authenticated user.
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/user/me",
|
||||
responses(
|
||||
(status = 200, description = "User information retrieved successfully", body = UserInfo),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
tag = USER_TAG,
|
||||
)]
|
||||
pub async fn get_user_info(
|
||||
State(app_state): State<Arc<AppState>>,
|
||||
request_info: Extension<Arc<RequestInfo>>,
|
||||
) -> Response {
|
||||
let user_id = match request_info.user_id {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
error!("User ID not found in request info");
|
||||
return (StatusCode::UNAUTHORIZED).into_response();
|
||||
}
|
||||
};
|
||||
|
||||
match app_state.service.user.get_user_by_id(user_id, None).await {
|
||||
Ok(user) => {
|
||||
let user_info = UserInfo {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
};
|
||||
(StatusCode::OK, Json(user_info)).into_response()
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Error fetching user info: {}", err);
|
||||
(StatusCode::INTERNAL_SERVER_ERROR).into_response()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,34 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/user/me": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "Get current user information",
|
||||
"description": "Returns the information of the currently authenticated user.",
|
||||
"operationId": "get_user_info",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "User information retrieved successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UserInfo"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized"
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal server error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
@@ -183,6 +211,25 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"UserInfo": {
|
||||
"type": "object",
|
||||
"description": "System health information",
|
||||
"required": [
|
||||
"id",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "User ID"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"description": "Username"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -194,6 +241,10 @@
|
||||
{
|
||||
"name": "Authentication",
|
||||
"description": "Authentication API"
|
||||
},
|
||||
{
|
||||
"name": "User",
|
||||
"description": "User management API"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user