feat: account deletion endpoints

This commit is contained in:
2026-10-26 02:49:07 +01:00
parent 54c8433c78
commit 0beedfbf0a
14 changed files with 420 additions and 8 deletions

View File

@@ -1,10 +1,12 @@
use crate::extractors::{Body, Upload};
use crate::extractors::{Body, PathId, Upload};
use crate::{errors::ApiError, extractors::AuthenticatedUser, state::AppState};
use api_types::{ProfileResponse, UserSummaryDto, UsersResponse};
use api_types::{DeleteAccountRequest, ProfileResponse, UserSummaryDto, UsersResponse};
use application::users::{
get_users, queries::GetUsersQuery, update_profile, update_profile_fields,
get_users, queries::GetUsersQuery, request_account_deletion, update_profile,
update_profile_fields,
};
use axum::{Json, extract::State, http::StatusCode, response::IntoResponse};
use domain::value_objects::UserId;
#[utoipa::path(
get, path = "/api/v1/profile",
@@ -155,3 +157,61 @@ pub async fn list_users(State(state): State<AppState>) -> Result<Json<UsersRespo
.collect(),
}))
}
async fn delete_account(
state: &AppState,
actor: UserId,
target: UserId,
password: &str,
) -> Result<StatusCode, ApiError> {
request_account_deletion::execute(
&state.app_ctx.deps.users.request_account_deletion,
actor,
target,
password,
)
.await?;
Ok(StatusCode::NO_CONTENT)
}
#[utoipa::path(
delete, path = "/api/v1/users/me",
request_body = DeleteAccountRequest,
responses(
(status = 204, description = "Account deleted"),
(status = 400, description = "Invalid input", body = api_types::ErrorResponse),
(status = 401, description = "Unauthorized or incorrect password", body = api_types::ErrorResponse),
(status = 409, description = "The last admin cannot be deleted", body = api_types::ErrorResponse),
),
security(("bearer_auth" = []))
)]
pub async fn delete_me(
State(state): State<AppState>,
AuthenticatedUser(user_id): AuthenticatedUser,
Body(req): Body<DeleteAccountRequest>,
) -> Result<StatusCode, ApiError> {
delete_account(&state, user_id.clone(), user_id, &req.password).await
}
#[utoipa::path(
delete, path = "/api/v1/users/{id}",
params(("id" = uuid::Uuid, Path, description = "User ID")),
request_body = DeleteAccountRequest,
responses(
(status = 204, description = "Account deleted"),
(status = 400, description = "Invalid input", body = api_types::ErrorResponse),
(status = 401, description = "Unauthorized or incorrect password", body = api_types::ErrorResponse),
(status = 403, description = "Admin only", body = api_types::ErrorResponse),
(status = 404, description = "User not found", body = api_types::ErrorResponse),
(status = 409, description = "The last admin cannot be deleted", body = api_types::ErrorResponse),
),
security(("bearer_auth" = []))
)]
pub async fn delete_user(
State(state): State<AppState>,
AuthenticatedUser(actor): AuthenticatedUser,
PathId(target): PathId<uuid::Uuid>,
Body(req): Body<DeleteAccountRequest>,
) -> Result<StatusCode, ApiError> {
delete_account(&state, actor, UserId::from_uuid(target), &req.password).await
}