2025-08-11 22:31:51 +07:00
use crate ::{ AppState , MetaRequestDto };
2025-05-18 03:12:20 +07:00
use crate ::{
MessageResponseDto , PermissionsEnum , ResponseListSuccessDto , ResponseSuccessDto ,
UsersCreateRequestDto , UsersDetailItemDto , permissions_guard ,
};
2025-08-14 13:16:39 +07:00
use axum ::extract ::{ Path , Multipart };
2025-03-30 02:46:16 +07:00
use axum ::http ::HeaderMap ;
2025-03-23 12:32:00 +07:00
use axum ::response ::IntoResponse ;
use axum ::{ Extension , Json };
2025-08-14 16:53:14 +07:00
use utoipa ::ToSchema ;
use serde ::{ Deserialize , Serialize };
2025-03-23 12:32:00 +07:00
2025-05-18 03:12:20 +07:00
use super ::{
UsersActiveInactiveRequestDto , UsersListItemDto , UsersUpdateRequestDto ,
2025-03-23 12:32:00 +07:00
};
2025-08-11 22:31:51 +07:00
use crate ::v1 ::users ::users_service ::{ UsersServiceTrait , UsersService };
2025-03-23 12:32:00 +07:00
2025-08-14 16:53:14 +07:00
#[derive(Serialize, Deserialize, ToSchema)]
#[schema(description = "File upload form data for multipart/form-data" )]
pub struct FileUploadSchema {
/// Binary file data to upload
#[schema(format = "binary" )]
pub file : String ,
}
2025-03-23 12:32:00 +07:00
#[utoipa::path(
get,
2025-03-26 13:06:34 +07:00
security(
( "Bearer" = [])
),
2025-03-23 12:32:00 +07:00
path = "/v1/users" ,
params(
( "page" = Option<i64>, Query, description = "Page number" ),
( "per_page" = Option<i64>, Query, description = "Items per page" ),
( "search" = Option<String>, Query, description = "Search keyword" ),
( "sort_by" = Option<String>, Query, description = "Sort by field" ),
( "order" = Option<String>, Query, description = "Order ASC or DESC" ),
( "filter" = Option<String>, Query, description = "Filter value" ),
( "filter_by" = Option<String>, Query, description = "Field to filter by" ),
),
responses(
2025-03-30 02:46:16 +07:00
(status = 200, description = "Get user list" , body = ResponseListSuccessDto<Vec<UsersListItemDto>>)
2025-03-23 12:32:00 +07:00
),
tag = "Users"
)]
pub async fn get_user_list (
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-23 12:32:00 +07:00
Extension ( state ) : Extension < AppState > ,
2025-08-12 18:53:11 +07:00
axum ::extract ::Query ( meta ) : axum ::extract ::Query < MetaRequestDto > ,
2025-03-23 12:32:00 +07:00
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard (
& headers ,
state . clone (),
vec! [ PermissionsEnum ::ReadListUsers ],
)
. await
{
Ok ( _ ) => UsersService ::get_user_list ( & state , meta ). await ,
Err ( response ) => response ,
}
2025-03-23 12:32:00 +07:00
}
#[utoipa::path(
get,
2025-03-26 13:06:34 +07:00
security(
( "Bearer" = [])
),
2025-03-23 12:32:00 +07:00
path = "/v1/users/detail/{id}" ,
params(
( "id" = String, Path, description = "User ID" )
),
responses(
2025-03-30 02:46:16 +07:00
(status = 200, description = "Get user by ID" , body = ResponseSuccessDto<UsersDetailItemDto>)
2025-03-23 12:32:00 +07:00
),
tag = "Users"
)]
pub async fn get_user_by_id (
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-23 12:32:00 +07:00
Extension ( state ) : Extension < AppState > ,
Path ( id ) : Path < String > ,
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard (
& headers ,
state . clone (),
2025-08-14 13:16:39 +07:00
vec! [ PermissionsEnum ::ReadListUsers ],
2025-04-02 09:35:37 +07:00
)
. await
{
Ok ( _ ) => UsersService ::get_user_by_id ( & state , id ). await ,
Err ( response ) => response ,
}
2025-03-23 12:32:00 +07:00
}
2025-03-30 02:46:16 +07:00
#[utoipa::path(
get,
security(
( "Bearer" = [])
),
path = "/v1/users/me" ,
responses(
(status = 200, description = "Get user by ID" , body = ResponseSuccessDto<UsersDetailItemDto>)
),
tag = "Users"
)]
pub async fn get_user_me (
Extension ( state ) : Extension < AppState > ,
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-30 02:46:16 +07:00
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard ( & headers , state . clone (), vec! []). await {
Ok ( _ ) => UsersService ::get_user_me ( headers , & state ). await ,
Err ( response ) => response ,
}
2025-03-30 02:46:16 +07:00
}
2025-03-23 12:32:00 +07:00
#[utoipa::path(
post,
2025-03-26 13:06:34 +07:00
security(
( "Bearer" = [])
),
2025-03-23 12:32:00 +07:00
path = "/v1/users/create" ,
request_body = UsersCreateRequestDto,
responses(
2025-08-14 13:16:39 +07:00
(status = 200, description = "Create new user" , body = ResponseSuccessDto<UsersDetailItemDto>)
2025-03-23 12:32:00 +07:00
),
tag = "Users"
)]
pub async fn post_create_user (
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-23 12:32:00 +07:00
Extension ( state ) : Extension < AppState > ,
Json ( payload ) : Json < UsersCreateRequestDto > ,
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard (
& headers ,
state . clone (),
vec! [ PermissionsEnum ::CreateUsers ],
)
. await
{
Ok ( _ ) => UsersService ::create_user ( & state , payload ). await ,
Err ( response ) => response ,
}
2025-03-23 12:32:00 +07:00
}
#[utoipa::path(
put,
2025-03-26 13:06:34 +07:00
security(
( "Bearer" = [])
),
2025-03-23 12:32:00 +07:00
path = "/v1/users/update/{id}" ,
2025-08-14 13:16:39 +07:00
params(
( "id" = String, Path, description = "User ID" )
),
2025-03-30 02:46:16 +07:00
request_body = UsersUpdateRequestDto,
2025-03-23 12:32:00 +07:00
responses(
2025-08-14 13:16:39 +07:00
(status = 200, description = "Update user" , body = ResponseSuccessDto<UsersDetailItemDto>)
2025-03-23 12:32:00 +07:00
),
tag = "Users"
)]
pub async fn put_update_user (
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-23 12:32:00 +07:00
Extension ( state ) : Extension < AppState > ,
Path ( id ) : Path < String > ,
Json ( payload ) : Json < UsersUpdateRequestDto > ,
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard (
& headers ,
state . clone (),
vec! [ PermissionsEnum ::UpdateUsers ],
)
. await
{
Ok ( _ ) => UsersService ::update_user ( & state , id , payload ). await ,
Err ( response ) => response ,
}
2025-03-23 12:32:00 +07:00
}
2025-03-30 02:46:16 +07:00
#[utoipa::path(
put,
security(
( "Bearer" = [])
),
path = "/v1/users/update/me" ,
request_body = UsersUpdateRequestDto,
responses(
2025-08-14 13:16:39 +07:00
(status = 200, description = "Update current user" , body = ResponseSuccessDto<UsersDetailItemDto>)
2025-03-30 02:46:16 +07:00
),
tag = "Users"
)]
pub async fn put_update_user_me (
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-30 02:46:16 +07:00
Extension ( state ) : Extension < AppState > ,
Json ( payload ) : Json < UsersUpdateRequestDto > ,
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard ( & headers , state . clone (), vec! []). await {
2025-08-11 22:31:51 +07:00
Ok ( _ ) => UsersService ::update_user_me ( headers , & state , payload ). await ,
2025-04-02 09:35:37 +07:00
Err ( response ) => response ,
}
2025-03-30 02:46:16 +07:00
}
2025-03-23 12:32:00 +07:00
#[utoipa::path(
put,
2025-03-26 13:06:34 +07:00
security(
( "Bearer" = [])
),
2025-03-23 12:32:00 +07:00
path = "/v1/users/activate/{id}" ,
2025-08-14 13:16:39 +07:00
params(
( "id" = String, Path, description = "User ID" )
),
2025-03-23 12:32:00 +07:00
request_body = UsersActiveInactiveRequestDto,
responses(
2025-08-14 13:16:39 +07:00
(status = 200, description = "Set user active status" , body = MessageResponseDto)
2025-03-23 12:32:00 +07:00
),
tag = "Users"
)]
pub async fn patch_user_active_status (
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-23 12:32:00 +07:00
Extension ( state ) : Extension < AppState > ,
2025-04-02 09:35:37 +07:00
Path ( id ) : Path < String > ,
2025-03-23 12:32:00 +07:00
Json ( payload ) : Json < UsersActiveInactiveRequestDto > ,
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard (
& headers ,
state . clone (),
2025-05-18 03:12:20 +07:00
vec! [ PermissionsEnum ::ActivateUsers ],
2025-04-02 09:35:37 +07:00
)
. await
{
Ok ( _ ) => UsersService ::set_user_active_status ( & state , id , payload ). await ,
Err ( response ) => response ,
}
2025-03-23 12:32:00 +07:00
}
#[utoipa::path(
delete,
2025-03-26 13:06:34 +07:00
security(
( "Bearer" = [])
),
2025-03-23 12:32:00 +07:00
path = "/v1/users/delete/{id}" ,
responses(
(status = 200, description = "Soft delete user" , body = MessageResponseDto)
),
tag = "Users"
)]
pub async fn delete_user (
2025-04-02 09:35:37 +07:00
headers : HeaderMap ,
2025-03-23 12:32:00 +07:00
Extension ( state ) : Extension < AppState > ,
Path ( id ) : Path < String > ,
) -> impl IntoResponse {
2025-04-02 09:35:37 +07:00
match permissions_guard (
& headers ,
state . clone (),
vec! [ PermissionsEnum ::DeleteUsers ],
)
. await
{
Ok ( _ ) => UsersService ::delete_user ( & state , id ). await ,
Err ( response ) => response ,
}
2025-03-23 12:32:00 +07:00
}
2025-08-14 13:16:39 +07:00
#[utoipa::path(
post,
security(
( "Bearer" = [])
),
path = "/v1/users/upload" ,
2025-08-14 16:53:14 +07:00
request_body(
content = FileUploadSchema,
description = "Upload file with multipart form data. Only 'file' field is required - file type will be detected automatically from the uploaded file." ,
content_type = "multipart/form-data"
),
2025-08-14 13:16:39 +07:00
responses(
(status = 200, description = "Upload file successfully" , body = ResponseSuccessDto<serde_json::Value>),
(status = 400, description = "Bad request" ),
(status = 401, description = "Unauthorized" ),
(status = 500, description = "Internal server error" )
),
tag = "Users"
)]
pub async fn upload_file (
headers : HeaderMap ,
Extension ( state ) : Extension < AppState > ,
multipart : Multipart ,
) -> impl IntoResponse {
// Check authentication first
match permissions_guard (
& headers ,
state . clone (),
vec! [], // No specific permission needed, just authentication
)
. await
{
Ok ( user ) => {
// Extract user ID from user data
let user_id = user . id . to_string ();
// Process upload - don't use match here since it returns Response directly
UsersService ::upload_file ( & state , user_id , multipart ). await
},
Err ( response ) => response ,
}
}