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!("Failed to delete app passwords for user {}: {:?}", user_id, e);
125 return (
126 StatusCode::INTERNAL_SERVER_ERROR,
127 Json(json!({"error": "InternalError", "message": "Failed to delete app passwords"})),
128 )
129 .into_response();
130 }
131 if let Err(e) = sqlx::query!("DELETE FROM invite_code_uses WHERE used_by_user = $1", user_id)
132 .execute(&mut *tx)
133 .await
134 {
135 error!("Failed to delete invite code uses for user {}: {:?}", user_id, e);
136 }
137 if let Err(e) = sqlx::query!("DELETE FROM invite_codes WHERE created_by_user = $1", user_id)
138 .execute(&mut *tx)
139 .await
140 {
141 error!("Failed to delete invite codes for user {}: {:?}", user_id, e);
142 }
143 if let Err(e) = sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
144 .execute(&mut *tx)
145 .await
146 {
147 error!("Failed to delete user keys for user {}: {:?}", user_id, e);
148 return (
149 StatusCode::INTERNAL_SERVER_ERROR,
150 Json(json!({"error": "InternalError", "message": "Failed to delete user keys"})),
151 )
152 .into_response();
153 }
154 if let Err(e) = sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
155 .execute(&mut *tx)
156 .await
157 {
158 error!("Failed to delete user {}: {:?}", user_id, e);
159 return (
160 StatusCode::INTERNAL_SERVER_ERROR,
161 Json(json!({"error": "InternalError", "message": "Failed to delete user"})),
162 )
163 .into_response();
164 }
165 if let Err(e) = tx.commit().await {
166 error!("Failed to commit account deletion transaction: {:?}", e);
167 return (
168 StatusCode::INTERNAL_SERVER_ERROR,
169 Json(json!({"error": "InternalError", "message": "Failed to commit deletion"})),
170 )
171 .into_response();
172 }
173 if let Err(e) = crate::api::repo::record::sequence_account_event(&state, did, false, Some("deleted")).await {
174 warn!("Failed to sequence account deletion event for {}: {}", did, e);
175 }
176 let _ = state.cache.delete(&format!("handle:{}", handle)).await;
177 (StatusCode::OK, Json(json!({}))).into_response()
178}