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 (k, v) = pair.split_once('=')?; 97 98 if k == key { 99 Some(urlencoding::decode(v).ok()?.into_owned()) 100 } else { 101 None 102 } 103 }) 104 .collect() 105 }) 106 .unwrap_or_default() 107} 108 109pub async fn get_account_infos( 110 State(state): State<AppState>, 111 _auth: BearerAuthAdmin, 112 RawQuery(raw_query): RawQuery, 113) -> Response { 114 let dids = parse_repeated_param(raw_query.as_deref(), "dids"); 115 if dids.is_empty() { 116 return ( 117 StatusCode::BAD_REQUEST, 118 Json(json!({"error": "InvalidRequest", "message": "dids is required"})), 119 ) 120 .into_response(); 121 } 122 let mut infos = Vec::new(); 123 for did in &dids { 124 if did.is_empty() { 125 continue; 126 } 127 let result = sqlx::query!( 128 r#" 129 SELECT did, handle, email, created_at 130 FROM users 131 WHERE did = $1 132 "#, 133 did 134 ) 135 .fetch_optional(&state.db) 136 .await; 137 if let Ok(Some(row)) = result { 138 infos.push(AccountInfo { 139 did: row.did, 140 handle: row.handle, 141 email: row.email, 142 indexed_at: row.created_at.to_rfc3339(), 143 invite_note: None, 144 invites_disabled: false, 145 email_verified_at: None, 146 deactivated_at: None, 147 }); 148 } 149 } 150 (StatusCode::OK, Json(GetAccountInfosOutput { infos })).into_response() 151}