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;
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
31 let did = input.did.trim();
32 if did.is_empty() {
33 return (
34 StatusCode::BAD_REQUEST,
35 Json(json!({"error": "InvalidRequest", "message": "did is required"})),
36 )
37 .into_response();
38 }
39
40 let user = sqlx::query!("SELECT id, handle FROM users WHERE did = $1", did)
41 .fetch_optional(&state.db)
42 .await;
43
44 let (user_id, handle) = match user {
45 Ok(Some(row)) => (row.id, row.handle),
46 Ok(None) => {
47 return (
48 StatusCode::NOT_FOUND,
49 Json(json!({"error": "AccountNotFound", "message": "Account not found"})),
50 )
51 .into_response();
52 }
53 Err(e) => {
54 error!("DB error in delete_account: {:?}", e);
55 return (
56 StatusCode::INTERNAL_SERVER_ERROR,
57 Json(json!({"error": "InternalError"})),
58 )
59 .into_response();
60 }
61 };
62
63 let mut tx = match state.db.begin().await {
64 Ok(tx) => tx,
65 Err(e) => {
66 error!("Failed to begin transaction for account deletion: {:?}", e);
67 return (
68 StatusCode::INTERNAL_SERVER_ERROR,
69 Json(json!({"error": "InternalError"})),
70 )
71 .into_response();
72 }
73 };
74
75 if let Err(e) = sqlx::query!("DELETE FROM session_tokens WHERE did = $1", did)
76 .execute(&mut *tx)
77 .await
78 {
79 error!("Failed to delete session tokens for {}: {:?}", did, e);
80 return (
81 StatusCode::INTERNAL_SERVER_ERROR,
82 Json(json!({"error": "InternalError", "message": "Failed to delete session tokens"})),
83 )
84 .into_response();
85 }
86
87 if let Err(e) = sqlx::query!("DELETE FROM used_refresh_tokens WHERE session_id IN (SELECT id FROM session_tokens WHERE did = $1)", did)
88 .execute(&mut *tx)
89 .await
90 {
91 error!("Failed to delete used refresh tokens for {}: {:?}", did, e);
92 }
93
94 if let Err(e) = sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
95 .execute(&mut *tx)
96 .await
97 {
98 error!("Failed to delete records for user {}: {:?}", user_id, e);
99 return (
100 StatusCode::INTERNAL_SERVER_ERROR,
101 Json(json!({"error": "InternalError", "message": "Failed to delete records"})),
102 )
103 .into_response();
104 }
105
106 if let Err(e) = sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
107 .execute(&mut *tx)
108 .await
109 {
110 error!("Failed to delete repos for user {}: {:?}", user_id, e);
111 return (
112 StatusCode::INTERNAL_SERVER_ERROR,
113 Json(json!({"error": "InternalError", "message": "Failed to delete repos"})),
114 )
115 .into_response();
116 }
117
118 if let Err(e) = sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
119 .execute(&mut *tx)
120 .await
121 {
122 error!("Failed to delete blobs for user {}: {:?}", user_id, e);
123 return (
124 StatusCode::INTERNAL_SERVER_ERROR,
125 Json(json!({"error": "InternalError", "message": "Failed to delete blobs"})),
126 )
127 .into_response();
128 }
129
130 if let Err(e) = sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1", user_id)
131 .execute(&mut *tx)
132 .await
133 {
134 error!("Failed to delete app passwords for user {}: {:?}", user_id, e);
135 return (
136 StatusCode::INTERNAL_SERVER_ERROR,
137 Json(json!({"error": "InternalError", "message": "Failed to delete app passwords"})),
138 )
139 .into_response();
140 }
141
142 if let Err(e) = sqlx::query!("DELETE FROM invite_code_uses WHERE used_by_user = $1", user_id)
143 .execute(&mut *tx)
144 .await
145 {
146 error!("Failed to delete invite code uses for user {}: {:?}", user_id, e);
147 }
148
149 if let Err(e) = sqlx::query!("DELETE FROM invite_codes WHERE created_by_user = $1", user_id)
150 .execute(&mut *tx)
151 .await
152 {
153 error!("Failed to delete invite codes for user {}: {:?}", user_id, e);
154 }
155
156 if let Err(e) = sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
157 .execute(&mut *tx)
158 .await
159 {
160 error!("Failed to delete user keys for user {}: {:?}", user_id, e);
161 return (
162 StatusCode::INTERNAL_SERVER_ERROR,
163 Json(json!({"error": "InternalError", "message": "Failed to delete user keys"})),
164 )
165 .into_response();
166 }
167
168 if let Err(e) = sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
169 .execute(&mut *tx)
170 .await
171 {
172 error!("Failed to delete user {}: {:?}", user_id, e);
173 return (
174 StatusCode::INTERNAL_SERVER_ERROR,
175 Json(json!({"error": "InternalError", "message": "Failed to delete user"})),
176 )
177 .into_response();
178 }
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
189 let _ = state.cache.delete(&format!("handle:{}", handle)).await;
190
191 (StatusCode::OK, Json(json!({}))).into_response()
192}