User listing, deleting and updating

This commit is contained in:
2026-04-25 14:33:02 +02:00
parent 6c1c13e088
commit f63131ebc7
3 changed files with 165 additions and 20 deletions
+142 -8
View File
@@ -6,7 +6,7 @@ use argon2::{
};
use axum::{
Extension, Json,
extract::State,
extract::{Path, State},
http::{Response, StatusCode, header},
response::IntoResponse,
};
@@ -18,7 +18,7 @@ use serde_json::json;
use crate::{
AppState,
cookie::jwt::encode_token,
models::{FilteredUser, LoginModel, LoginScheme, UserCreateScheme},
models::{FilteredUser, LoginScheme, User, UserCreateScheme, UserUpdateScheme},
};
pub async fn create_user(
@@ -88,7 +88,7 @@ pub async fn login(
State(data): State<Arc<AppState>>,
Json(request): Json<LoginScheme>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let user = sqlx::query_as::<_, LoginModel>(r#"SELECT * FROM users WHERE username = $1"#)
let user = sqlx::query_as::<_, User>(r#"SELECT * FROM users WHERE username = $1"#)
.bind(request.username)
.fetch_optional(&data.db)
.await
@@ -131,7 +131,7 @@ pub async fn login(
.http_only(true);
let mut response = Response::new(
json!({"status": "success", "token": token, "user": filter_users(&user)}).to_string(),
json!({"status": "success", "token": token, "user": filter_user(&user)}).to_string(),
);
response
.headers_mut()
@@ -156,24 +156,158 @@ pub async fn logout() -> Result<impl IntoResponse, (StatusCode, Json<serde_json:
}
pub async fn get_current_user(
Extension(state): Extension<LoginModel>,
Extension(state): Extension<User>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let response = json!({
"status": "success",
"data": json!({
"first_name": filter_users(&state).first_name,
"last_name": filter_users(&state).last_name
"first_name": filter_user(&state).first_name,
"last_name": filter_user(&state).last_name
})
});
Ok(Json(response))
}
fn filter_users(user: &LoginModel) -> FilteredUser {
pub async fn delete_user(
Path(id): Path<i32>,
State(data): State<Arc<AppState>>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let query = sqlx::query(r#"DELETE FROM users WHERE id = $1"#)
.bind(id)
.execute(&data.db)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
)
})?;
if query.rows_affected() == 0 {
let error = json!({
"status": "error",
"message": format!("User with ID {} not found", id)
});
return Err((StatusCode::NOT_FOUND, Json(error)));
}
Ok(StatusCode::NO_CONTENT)
}
pub async fn get_users(
State(data): State<Arc<AppState>>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let users = sqlx::query_as::<_, User>(r#"SELECT * FROM users ORDER BY last_name ASC"#)
.fetch_all(&data.db)
.await
.map_err(|e| {
let error = json!({
"status": "error",
"message": format!("{:?}", e)
});
(StatusCode::INTERNAL_SERVER_ERROR, Json(error))
})?;
let response = users
.iter()
.map(|user| filter_user(&user))
.collect::<Vec<FilteredUser>>();
let json_respnse = json!(response);
Ok(Json(json_respnse))
}
pub async fn get_user_by_id(
Path(id): Path<i32>,
State(data): State<Arc<AppState>>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let query = sqlx::query_as::<_, User>(r#"SELECT * FROM users WHERE id = $1"#)
.bind(id)
.fetch_one(&data.db)
.await;
match query {
Ok(user) => {
let response = serde_json::json!(filter_user(&user));
return Ok(Json(response));
}
Err(sqlx::Error::RowNotFound) => {
let error_response = serde_json::json!({
"status": "fail",
"message": format!("User with ID {} not found", id)
});
return Err((StatusCode::NOT_FOUND, Json(error_response)));
}
Err(e) => {
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
));
}
};
}
pub async fn update_user(
Path(id): Path<i32>,
State(data): State<Arc<AppState>>,
Json(body): Json<UserUpdateScheme>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let argon = Argon2::default();
let salt = SaltString::generate(&mut OsRng);
let hashed_pwd = match argon.hash_password(body.new_pwd.clone().as_bytes(), &salt) {
Ok(h) => h.to_string(),
Err(e) => panic!("Error hashing {:}", e),
};
let update_result = sqlx::query(r#"UPDATE users SET first_name = $1, last_name = $2, username = $3, pwd = $4, is_admin = $5 WHERE id = $6"#)
.bind(body.first_name.to_owned())
.bind(body.last_name.to_owned())
.bind(body.username.to_owned())
.bind(hashed_pwd)
.bind(body.make_admin.to_owned())
.bind(id)
.execute(&data.db)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
)
})?;
if update_result.rows_affected() == 0 {
let error_response = serde_json::json!({
"status": "error",
"message": format!("User with ID {} not found", id)
});
return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(error_response)));
}
let updated_user = sqlx::query_as::<_, User>(r#"SELECT * FROM users WHERE id = $1"#)
.bind(id)
.fetch_one(&data.db)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
)
})?;
let response = serde_json::json!({
"user": filter_user(&updated_user),
"status": "success"
});
Ok(Json(response))
}
fn filter_user(user: &User) -> FilteredUser {
FilteredUser {
id: user.id,
first_name: user.first_name.clone(),
last_name: user.last_name.clone(),
username: user.username.clone(),
is_admin: user.is_admin.clone(),
}
}