this repo has no description
1use crate::api::EmptyResponse;
2use crate::api::error::ApiError;
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()))
51 .into_response();
52 }
53 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())
54 .execute(&mut *tx)
55 .await
56 {
57 error!("Failed to delete used refresh tokens for {}: {:?}", did, e);
58 }
59 if let Err(e) = sqlx::query!("DELETE FROM records WHERE repo_id = $1", user_id)
60 .execute(&mut *tx)
61 .await
62 {
63 error!("Failed to delete records for user {}: {:?}", user_id, e);
64 return ApiError::InternalError(Some("Failed to delete records".into())).into_response();
65 }
66 if let Err(e) = sqlx::query!("DELETE FROM repos WHERE user_id = $1", user_id)
67 .execute(&mut *tx)
68 .await
69 {
70 error!("Failed to delete repos for user {}: {:?}", user_id, e);
71 return ApiError::InternalError(Some("Failed to delete repos".into())).into_response();
72 }
73 if let Err(e) = sqlx::query!("DELETE FROM blobs WHERE created_by_user = $1", user_id)
74 .execute(&mut *tx)
75 .await
76 {
77 error!("Failed to delete blobs for user {}: {:?}", user_id, e);
78 return ApiError::InternalError(Some("Failed to delete blobs".into())).into_response();
79 }
80 if let Err(e) = sqlx::query!("DELETE FROM app_passwords WHERE user_id = $1", user_id)
81 .execute(&mut *tx)
82 .await
83 {
84 error!(
85 "Failed to delete app passwords for user {}: {:?}",
86 user_id, e
87 );
88 return ApiError::InternalError(Some("Failed to delete app passwords".into()))
89 .into_response();
90 }
91 if let Err(e) = sqlx::query!(
92 "DELETE FROM invite_code_uses WHERE used_by_user = $1",
93 user_id
94 )
95 .execute(&mut *tx)
96 .await
97 {
98 error!(
99 "Failed to delete invite code uses for user {}: {:?}",
100 user_id, e
101 );
102 }
103 if let Err(e) = sqlx::query!(
104 "DELETE FROM invite_codes WHERE created_by_user = $1",
105 user_id
106 )
107 .execute(&mut *tx)
108 .await
109 {
110 error!(
111 "Failed to delete invite codes for user {}: {:?}",
112 user_id, e
113 );
114 }
115 if let Err(e) = sqlx::query!("DELETE FROM user_keys WHERE user_id = $1", user_id)
116 .execute(&mut *tx)
117 .await
118 {
119 error!("Failed to delete user keys for user {}: {:?}", user_id, e);
120 return ApiError::InternalError(Some("Failed to delete user keys".into())).into_response();
121 }
122 if let Err(e) = sqlx::query!("DELETE FROM users WHERE id = $1", user_id)
123 .execute(&mut *tx)
124 .await
125 {
126 error!("Failed to delete user {}: {:?}", user_id, e);
127 return ApiError::InternalError(Some("Failed to delete user".into())).into_response();
128 }
129 if let Err(e) = tx.commit().await {
130 error!("Failed to commit account deletion transaction: {:?}", e);
131 return ApiError::InternalError(Some("Failed to commit deletion".into())).into_response();
132 }
133 if let Err(e) =
134 crate::api::repo::record::sequence_account_event(&state, did, false, Some("deleted")).await
135 {
136 warn!(
137 "Failed to sequence account deletion event for {}: {}",
138 did, e
139 );
140 }
141 let _ = state.cache.delete(&format!("handle:{}", handle)).await;
142 EmptyResponse::ok().into_response()
143}