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