187 lines
4.6 KiB
Rust
187 lines
4.6 KiB
Rust
use axum::{
|
|
extract::{Path, State},
|
|
http::StatusCode,
|
|
response::Json,
|
|
routing::{get, post, put, delete},
|
|
Router,
|
|
};
|
|
use std::sync::Arc;
|
|
use uuid::Uuid;
|
|
|
|
use crate::{
|
|
auth::AuthUser,
|
|
models::{CreateUser, UpdateUser, UserResponse, UserRole},
|
|
AppState,
|
|
};
|
|
|
|
fn require_admin(auth_user: &AuthUser) -> Result<(), StatusCode> {
|
|
if auth_user.user.role != UserRole::Admin {
|
|
Err(StatusCode::FORBIDDEN)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub fn router() -> Router<Arc<AppState>> {
|
|
Router::new()
|
|
.route("/", get(list_users).post(create_user))
|
|
.route("/{id}", get(get_user).put(update_user).delete(delete_user))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/api/users",
|
|
tag = "users",
|
|
security(
|
|
("bearer_auth" = [])
|
|
),
|
|
responses(
|
|
(status = 200, description = "List of all users", body = Vec<UserResponse>),
|
|
(status = 401, description = "Unauthorized")
|
|
)
|
|
)]
|
|
async fn list_users(
|
|
auth_user: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
) -> Result<Json<Vec<UserResponse>>, StatusCode> {
|
|
require_admin(&auth_user)?;
|
|
let users = state
|
|
.db
|
|
.get_all_users()
|
|
.await
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
|
|
let user_responses: Vec<UserResponse> = users.into_iter().map(|u| u.into()).collect();
|
|
Ok(Json(user_responses))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
get,
|
|
path = "/api/users/{id}",
|
|
tag = "users",
|
|
security(
|
|
("bearer_auth" = [])
|
|
),
|
|
params(
|
|
("id" = Uuid, Path, description = "User ID")
|
|
),
|
|
responses(
|
|
(status = 200, description = "User information", body = UserResponse),
|
|
(status = 404, description = "User not found"),
|
|
(status = 401, description = "Unauthorized")
|
|
)
|
|
)]
|
|
async fn get_user(
|
|
auth_user: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
Path(id): Path<Uuid>,
|
|
) -> Result<Json<UserResponse>, StatusCode> {
|
|
require_admin(&auth_user)?;
|
|
let user = state
|
|
.db
|
|
.get_user_by_id(id)
|
|
.await
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
|
.ok_or(StatusCode::NOT_FOUND)?;
|
|
|
|
Ok(Json(user.into()))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
post,
|
|
path = "/api/users",
|
|
tag = "users",
|
|
security(
|
|
("bearer_auth" = [])
|
|
),
|
|
request_body = CreateUser,
|
|
responses(
|
|
(status = 200, description = "User created successfully", body = UserResponse),
|
|
(status = 400, description = "Bad request - invalid user data"),
|
|
(status = 401, description = "Unauthorized")
|
|
)
|
|
)]
|
|
async fn create_user(
|
|
auth_user: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
Json(user_data): Json<CreateUser>,
|
|
) -> Result<Json<UserResponse>, StatusCode> {
|
|
require_admin(&auth_user)?;
|
|
let user = state
|
|
.db
|
|
.create_user(user_data)
|
|
.await
|
|
.map_err(|_| StatusCode::BAD_REQUEST)?;
|
|
|
|
Ok(Json(user.into()))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
put,
|
|
path = "/api/users/{id}",
|
|
tag = "users",
|
|
security(
|
|
("bearer_auth" = [])
|
|
),
|
|
params(
|
|
("id" = Uuid, Path, description = "User ID")
|
|
),
|
|
request_body = UpdateUser,
|
|
responses(
|
|
(status = 200, description = "User updated successfully", body = UserResponse),
|
|
(status = 400, description = "Bad request - invalid user data"),
|
|
(status = 401, description = "Unauthorized")
|
|
)
|
|
)]
|
|
async fn update_user(
|
|
auth_user: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
Path(id): Path<Uuid>,
|
|
Json(update_data): Json<UpdateUser>,
|
|
) -> Result<Json<UserResponse>, StatusCode> {
|
|
require_admin(&auth_user)?;
|
|
let user = state
|
|
.db
|
|
.update_user(id, update_data.username, update_data.email, update_data.password)
|
|
.await
|
|
.map_err(|_| StatusCode::BAD_REQUEST)?;
|
|
|
|
Ok(Json(user.into()))
|
|
}
|
|
|
|
#[utoipa::path(
|
|
delete,
|
|
path = "/api/users/{id}",
|
|
tag = "users",
|
|
security(
|
|
("bearer_auth" = [])
|
|
),
|
|
params(
|
|
("id" = Uuid, Path, description = "User ID")
|
|
),
|
|
responses(
|
|
(status = 204, description = "User deleted successfully"),
|
|
(status = 403, description = "Forbidden - cannot delete yourself"),
|
|
(status = 401, description = "Unauthorized")
|
|
)
|
|
)]
|
|
async fn delete_user(
|
|
auth_user: AuthUser,
|
|
State(state): State<Arc<AppState>>,
|
|
Path(id): Path<Uuid>,
|
|
) -> Result<StatusCode, StatusCode> {
|
|
require_admin(&auth_user)?;
|
|
|
|
// Prevent users from deleting themselves
|
|
if auth_user.user.id == id {
|
|
return Err(StatusCode::FORBIDDEN);
|
|
}
|
|
|
|
state
|
|
.db
|
|
.delete_user(id)
|
|
.await
|
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
|
|
|
Ok(StatusCode::NO_CONTENT)
|
|
} |