feat(server): user account deletion
This commit is contained in:
parent
6fd3499d7b
commit
20b8353cfb
9 changed files with 252 additions and 6 deletions
|
|
@ -188,6 +188,25 @@ pub async fn update_password_hash(pool: &Pool, user_id: i64, hash: &str) -> Resu
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Permanently deletes a user and their auth data.
|
||||
/// Game history rows are kept but de-associated (user_id set to NULL).
|
||||
pub async fn delete_user(pool: &Pool, user_id: i64) -> Result<(), DbError> {
|
||||
let client = pool.get().await?;
|
||||
client
|
||||
.execute(
|
||||
"UPDATE game_participants SET user_id = NULL WHERE user_id = $1",
|
||||
&[&user_id],
|
||||
)
|
||||
.await?;
|
||||
client
|
||||
.execute("DELETE FROM email_tokens WHERE user_id = $1", &[&user_id])
|
||||
.await?;
|
||||
client
|
||||
.execute("DELETE FROM users WHERE id = $1", &[&user_id])
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ── Email tokens ──────────────────────────────────────────────────────────────
|
||||
|
||||
pub async fn create_email_token(
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use axum::{
|
|||
extract::{Path, Query, State},
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
routing::{get, post},
|
||||
routing::{delete, get, post},
|
||||
};
|
||||
use axum_login::AuthSession;
|
||||
use rand::distributions::Alphanumeric;
|
||||
|
|
@ -48,6 +48,7 @@ pub fn router() -> Router<Arc<AppState>> {
|
|||
.route("/auth/resend-verification", post(resend_verification))
|
||||
.route("/auth/forgot-password", post(forgot_password))
|
||||
.route("/auth/reset-password", post(reset_password))
|
||||
.route("/auth/account", delete(delete_account))
|
||||
.route("/users/{username}", get(user_profile))
|
||||
.route("/users/{username}/games", get(user_games))
|
||||
.route("/games/result", post(game_result))
|
||||
|
|
@ -286,6 +287,16 @@ async fn logout(mut auth_session: AuthSession<AuthBackend>) -> Result<StatusCode
|
|||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
async fn delete_account(
|
||||
mut auth_session: AuthSession<AuthBackend>,
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Result<StatusCode, AppError> {
|
||||
let user = auth_session.user.clone().ok_or(AppError::Unauthorized)?;
|
||||
auth_session.logout().await.map_err(|_| AppError::Internal)?;
|
||||
db::delete_user(&state.db, user.id).await?;
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
async fn me(auth_session: AuthSession<AuthBackend>) -> Result<impl IntoResponse, AppError> {
|
||||
match auth_session.user {
|
||||
Some(user) => Ok(Json(MeResponse {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ async fn main() {
|
|||
.allow_origin(AllowOrigin::list([
|
||||
"http://localhost:9091".parse().unwrap(), // unified web dev server
|
||||
]))
|
||||
.allow_methods([Method::GET, Method::POST, Method::OPTIONS])
|
||||
.allow_methods([Method::GET, Method::POST, Method::DELETE, Method::OPTIONS])
|
||||
.allow_headers([
|
||||
HeaderName::from_static("content-type"),
|
||||
HeaderName::from_static("cookie"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue