this repo has no description
1use crate::auth::BearerAuthAdmin; 2use crate::state::AppState; 3use axum::{ 4 Json, 5 extract::{Query, RawQuery, State}, 6 http::StatusCode, 7 response::{IntoResponse, Response}, 8}; 9use serde::{Deserialize, Serialize}; 10use serde_json::json; 11use tracing::error; 12 13#[derive(Deserialize)] 14pub struct GetAccountInfoParams { 15 pub did: String, 16} 17 18#[derive(Serialize)] 19#[serde(rename_all = "camelCase")] 20pub struct AccountInfo { 21 pub did: String, 22 pub handle: String, 23 pub email: Option<String>, 24 pub indexed_at: String, 25 pub invite_note: Option<String>, 26 pub invites_disabled: bool, 27 pub email_verified_at: Option<String>, 28 pub deactivated_at: Option<String>, 29} 30 31#[derive(Serialize)] 32#[serde(rename_all = "camelCase")] 33pub struct GetAccountInfosOutput { 34 pub infos: Vec<AccountInfo>, 35} 36 37pub async fn get_account_info( 38 State(state): State<AppState>, 39 _auth: BearerAuthAdmin, 40 Query(params): Query<GetAccountInfoParams>, 41) -> Response { 42 let did = params.did.trim(); 43 if did.is_empty() { 44 return ( 45 StatusCode::BAD_REQUEST, 46 Json(json!({"error": "InvalidRequest", "message": "did is required"})), 47 ) 48 .into_response(); 49 } 50 let result = sqlx::query!( 51 r#" 52 SELECT did, handle, email, created_at 53 FROM users 54 WHERE did = $1 55 "#, 56 did 57 ) 58 .fetch_optional(&state.db) 59 .await; 60 match result { 61 Ok(Some(row)) => ( 62 StatusCode::OK, 63 Json(AccountInfo { 64 did: row.did, 65 handle: row.handle, 66 email: row.email, 67 indexed_at: row.created_at.to_rfc3339(), 68 invite_note: None, 69 invites_disabled: false, 70 email_verified_at: None, 71 deactivated_at: None, 72 }), 73 ) 74 .into_response(), 75 Ok(None) => ( 76 StatusCode::NOT_FOUND, 77 Json(json!({"error": "AccountNotFound", "message": "Account not found"})), 78 ) 79 .into_response(), 80 Err(e) => { 81 error!("DB error in get_account_info: {:?}", e); 82 ( 83 StatusCode::INTERNAL_SERVER_ERROR, 84 Json(json!({"error": "InternalError"})), 85 ) 86 .into_response() 87 } 88 } 89} 90 91fn parse_repeated_param(query: Option<&str>, key: &str) -> Vec<String> { 92 query 93 .map(|q| { 94 q.split('&') 95 .filter_map(|pair| { 96 let mut parts = pair.splitn(2, '='); 97 let k = parts.next()?; 98 let v = parts.next()?; 99 if k == key { 100 Some(urlencoding::decode(v).ok()?.into_owned()) 101 } else { 102 None 103 } 104 }) 105 .collect() 106 }) 107 .unwrap_or_default() 108} 109 110pub async fn get_account_infos( 111 State(state): State<AppState>, 112 _auth: BearerAuthAdmin, 113 RawQuery(raw_query): RawQuery, 114) -> Response { 115 let dids = parse_repeated_param(raw_query.as_deref(), "dids"); 116 if dids.is_empty() { 117 return ( 118 StatusCode::BAD_REQUEST, 119 Json(json!({"error": "InvalidRequest", "message": "dids is required"})), 120 ) 121 .into_response(); 122 } 123 let mut infos = Vec::new(); 124 for did in &dids { 125 if did.is_empty() { 126 continue; 127 } 128 let result = sqlx::query!( 129 r#" 130 SELECT did, handle, email, created_at 131 FROM users 132 WHERE did = $1 133 "#, 134 did 135 ) 136 .fetch_optional(&state.db) 137 .await; 138 if let Ok(Some(row)) = result { 139 infos.push(AccountInfo { 140 did: row.did, 141 handle: row.handle, 142 email: row.email, 143 indexed_at: row.created_at.to_rfc3339(), 144 invite_note: None, 145 invites_disabled: false, 146 email_verified_at: None, 147 deactivated_at: None, 148 }); 149 } 150 } 151 (StatusCode::OK, Json(GetAccountInfosOutput { infos })).into_response() 152}