this repo has no description
1use crate::state::AppState;
2use axum::{
3 Json,
4 extract::State,
5 http::StatusCode,
6 response::{IntoResponse, Response},
7};
8use serde::Deserialize;
9use serde_json::json;
10use tracing::{error, warn};
11
12#[derive(Deserialize)]
13pub struct DeleteAccountInput {
14 pub did: String,
15}
16
17pub async fn delete_account(
18 State(state): State<AppState>,
19 headers: axum::http::HeaderMap,
20 Json(input): Json<DeleteAccountInput>,
21) -> Response {
22 let auth_header = headers.get("Authorization");
23 if auth_header.is_none() {
24 return (
25 StatusCode::UNAUTHORIZED,
26 Json(json!({"error": "AuthenticationRequired"})),
27 )
28 .into_response();
29 }
30 let did = input.did.trim();
31 if did.is_empty() {
32 return (
33 StatusCode::BAD_REQUEST,
34 Json(json!({"error": "InvalidRequest", "message": "did is required"})),
35 )
36 .into_response();
37 }
38 let user = sqlx::query!("SELECT id, handle FROM users WHERE did = $1", did)
39 .fetch_optional(&state.db)
40 .await;
41 let (user_id, handle) = match user {
42 Ok(Some(row)) => (row.id, row.handle),
43 Ok(None) => {
44 return (
45 StatusCode::NOT_FOUND,
46 Json(json!({"error": "AccountNotFound", "message": "Account not found"})),
47 )
48 .into_response();
49 }
50 Err(e) => {
51 error!("DB error in delete_account: {:?}", e);
52 return (
53 StatusCode::INTERNAL_SERVER_ERROR,
54 Json(json!({"error": "InternalError"})),
55 )
56 .into_response();
57 }
58 };
59 let mut tx = match state.db.begin().await {
60 Ok(tx) => tx,
61 Err(e) => {
62 error!("Failed to begin transaction for account deletion: {:?}", e);
63 return (
64 StatusCode::INTERNAL_SERVER_ERROR,
65 Json(json!({"error": "InternalError"})),
66 )
67 .into_response();
68 }
69 };
70 if let Err(e) = sqlx::query!("DELETE FROM session_tokens WHERE did = $1", did)
71 .execute(&mut *tx)
72 .await
73 {
74 error!("Failed to delete session tokens for {}: {:?}", did, e);
75 return (
76 StatusCode::INTERNAL_SERVER_ERROR,
77 Json(json!({"error": "InternalError", "message": "Failed to delete session tokens"})),
78 )
79 .into_response();
80 }
81 if let Err(e) = sqlx::query!("DELETE FROM used_refresh_tokens WHERE session_id IN (SELECT id FROM session_tokens WHERE did = $1)", did)
82 .execute(&mut *tx)
83 .await
84 {
85 error!("Failed to delete used refresh tokens for {}: {:?}", did, e);
86 }
87 if let Err(e) = sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
88 .execute(&mut *tx)
89 .await
90 {
91 error!("Failed to delete records for user {}: {:?}", user_id, e);
92 return (
93 StatusCode::INTERNAL_SERVER_ERROR,
94 Json(json!({"error": "InternalError", "message": "Failed to delete records"})),
95 )
96 .into_response();
97 }
98 if let Err(e) = sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
99 .execute(&mut *tx)
100 .await
101 {
102 error!("Failed to delete repos for user {}: {:?}", user_id, e);
103 return (
104 StatusCode::INTERNAL_SERVER_ERROR,
105 Json(json!({"error": "InternalError", "message": "Failed to delete repos"})),
106 )
107 .into_response();
108 }
109 if let Err(e) = sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
110 .execute(&mut *tx)
111 .await
112 {
113 error!("Failed to delete blobs for user {}: {:?}", user_id, e);
114 return (
115 StatusCode::INTERNAL_SERVER_ERROR,
116 Json(json!({"error": "InternalError", "message": "Failed to delete blobs"})),
117 )
118 .into_response();
119 }
120 if let Err(e) = sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1", user_id)
121 .execute(&mut *tx)
122 .await
123 {
124 error!(
125 "Failed to delete app passwords for user {}: {:?}",
126 user_id, e
127 );
128 return (
129 StatusCode::INTERNAL_SERVER_ERROR,
130 Json(json!({"error": "InternalError", "message": "Failed to delete app passwords"})),
131 )
132 .into_response();
133 }
134 if let Err(e) = sqlx::query!(
135 "DELETE FROM invite_code_uses WHERE used_by_user = $1",
136 user_id
137 )
138 .execute(&mut *tx)
139 .await
140 {
141 error!(
142 "Failed to delete invite code uses for user {}: {:?}",
143 user_id, e
144 );
145 }
146 if let Err(e) = sqlx::query!(
147 "DELETE FROM invite_codes WHERE created_by_user = $1",
148 user_id
149 )
150 .execute(&mut *tx)
151 .await
152 {
153 error!(
154 "Failed to delete invite codes for user {}: {:?}",
155 user_id, e
156 );
157 }
158 if let Err(e) = sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
159 .execute(&mut *tx)
160 .await
161 {
162 error!("Failed to delete user keys for user {}: {:?}", user_id, e);
163 return (
164 StatusCode::INTERNAL_SERVER_ERROR,
165 Json(json!({"error": "InternalError", "message": "Failed to delete user keys"})),
166 )
167 .into_response();
168 }
169 if let Err(e) = sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
170 .execute(&mut *tx)
171 .await
172 {
173 error!("Failed to delete user {}: {:?}", user_id, e);
174 return (
175 StatusCode::INTERNAL_SERVER_ERROR,
176 Json(json!({"error": "InternalError", "message": "Failed to delete user"})),
177 )
178 .into_response();
179 }
180 if let Err(e) = tx.commit().await {
181 error!("Failed to commit account deletion transaction: {:?}", e);
182 return (
183 StatusCode::INTERNAL_SERVER_ERROR,
184 Json(json!({"error": "InternalError", "message": "Failed to commit deletion"})),
185 )
186 .into_response();
187 }
188 if let Err(e) =
189 crate::api::repo::record::sequence_account_event(&state, did, false, Some("deleted")).await
190 {
191 warn!(
192 "Failed to sequence account deletion event for {}: {}",
193 did, e
194 );
195 }
196 let _ = state.cache.delete(&format!("handle:{}", handle)).await;
197 (StatusCode::OK, Json(json!({}))).into_response()
198}