feature/frontend-login #10

Merged
GW_MC merged 24 commits from feature/frontend-login into master 2025-12-20 19:01:07 +08:00
6 changed files with 147 additions and 3 deletions
Showing only changes of commit e59e7ca4c8 - Show all commits

View File

@@ -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;

View File

@@ -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,

View 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)
}

View 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()
}
}
}

View File

@@ -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"
}
]
}

View File

@@ -9,6 +9,7 @@ export namespace Schemas {
version: string;
};
export type LoginRequest = { password: string; username: string };
export type UserInfo = { id: string; username: string };
// </Schemas>
}
@@ -41,6 +42,13 @@ export namespace Endpoints {
parameters: never;
responses: { 200: Schemas.HealthInfo; 404: unknown };
};
export type get_Get_user_info = {
method: "GET";
path: "/api/user/me";
requestFormat: "json";
parameters: never;
responses: { 200: Schemas.UserInfo; 401: unknown; 500: unknown };
};
// </Endpoints>
}
@@ -53,6 +61,7 @@ export type EndpointByMethod = {
};
get: {
"/api/health/info": Endpoints.get_Get_health_info;
"/api/user/me": Endpoints.get_Get_user_info;
};
};