this repo has no description
1use crate::api::error::ApiError;
2use crate::api::EmptyResponse;
3use crate::auth::BearerAuthAdmin;
4use crate::state::AppState;
5use crate::types::Did;
6use axum::{
7 Json,
8 extract::State,
9 response::{IntoResponse, Response},
10};
11use serde::Deserialize;
12use tracing::{error, warn};
13
14#[derive(Deserialize)]
15pub struct DeleteAccountInput {
16 pub did: Did,
17}
18
19pub async fn delete_account(
20 State(state): State<AppState>,
21 _auth: BearerAuthAdmin,
22 Json(input): Json<DeleteAccountInput>,
23) -> Response {
24 let did = &input.did;
25 let user = sqlx::query!("SELECT id, handle FROM users WHERE did = $1", did.as_str())
26 .fetch_optional(&state.db)
27 .await;
28 let (user_id, handle) = match user {
29 Ok(Some(row)) => (row.id, row.handle),
30 Ok(None) => {
31 return ApiError::AccountNotFound.into_response();
32 }
33 Err(e) => {
34 error!("DB error in delete_account: {:?}", e);
35 return ApiError::InternalError(None).into_response();
36 }
37 };
38 let mut tx = match state.db.begin().await {
39 Ok(tx) => tx,
40 Err(e) => {
41 error!("Failed to begin transaction for account deletion: {:?}", e);
42 return ApiError::InternalError(None).into_response();
43 }
44 };
45 if let Err(e) = sqlx::query!("DELETE FROM session_tokens WHERE did = $1", did.as_str())
46 .execute(&mut *tx)
47 .await
48 {
49 error!("Failed to delete session tokens for {}: {:?}", did, e);
50 return ApiError::InternalError(Some("Failed to delete session tokens".into())).into_response();
51 }
52 if let Err(e) = sqlx::query!("DELETE FROM used_refresh_tokens WHERE session_id IN (SELECT id FROM session_tokens WHERE did = $1)", did.as_str())
53 .execute(&mut *tx)
54 .await
55 {
56 error!("Failed to delete used refresh tokens for {}: {:?}", did, e);
57 }
58 if let Err(e) = sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
59 .execute(&mut *tx)
60 .await
61 {
62 error!("Failed to delete records for user {}: {:?}", user_id, e);
63 return ApiError::InternalError(Some("Failed to delete records".into())).into_response();
64 }
65 if let Err(e) = sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
66 .execute(&mut *tx)
67 .await
68 {
69 error!("Failed to delete repos for user {}: {:?}", user_id, e);
70 return ApiError::InternalError(Some("Failed to delete repos".into())).into_response();
71 }
72 if let Err(e) = sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
73 .execute(&mut *tx)
74 .await
75 {
76 error!("Failed to delete blobs for user {}: {:?}", user_id, e);
77 return ApiError::InternalError(Some("Failed to delete blobs".into())).into_response();
78 }
79 if let Err(e) = sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1", user_id)
80 .execute(&mut *tx)
81 .await
82 {
83 error!(
84 "Failed to delete app passwords for user {}: {:?}",
85 user_id, e
86 );
87 return ApiError::InternalError(Some("Failed to delete app passwords".into())).into_response();
88 }
89 if let Err(e) = sqlx::query!(
90 "DELETE FROM invite_code_uses WHERE used_by_user = $1",
91 user_id
92 )
93 .execute(&mut *tx)
94 .await
95 {
96 error!(
97 "Failed to delete invite code uses for user {}: {:?}",
98 user_id, e
99 );
100 }
101 if let Err(e) = sqlx::query!(
102 "DELETE FROM invite_codes WHERE created_by_user = $1",
103 user_id
104 )
105 .execute(&mut *tx)
106 .await
107 {
108 error!(
109 "Failed to delete invite codes for user {}: {:?}",
110 user_id, e
111 );
112 }
113 if let Err(e) = sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
114 .execute(&mut *tx)
115 .await
116 {
117 error!("Failed to delete user keys for user {}: {:?}", user_id, e);
118 return ApiError::InternalError(Some("Failed to delete user keys".into())).into_response();
119 }
120 if let Err(e) = sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
121 .execute(&mut *tx)
122 .await
123 {
124 error!("Failed to delete user {}: {:?}", user_id, e);
125 return ApiError::InternalError(Some("Failed to delete user".into())).into_response();
126 }
127 if let Err(e) = tx.commit().await {
128 error!("Failed to commit account deletion transaction: {:?}", e);
129 return ApiError::InternalError(Some("Failed to commit deletion".into())).into_response();
130 }
131 if let Err(e) =
132 crate::api::repo::record::sequence_account_event(&state, did.as_str(), false, Some("deleted")).await
133 {
134 warn!(
135 "Failed to sequence account deletion event for {}: {}",
136 did, e
137 );
138 }
139 let _ = state.cache.delete(&format!("handle:{}", handle)).await;
140 EmptyResponse::ok().into_response()
141}