use serde::{Deserialize, Serialize};
use reqwest::Client;
use anyhow::{anyhow, Result};
const BASE_URL: &str = "https://api.dev.amit.public.norman-ai.com/v0";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Account {
pub id: String,
pub creation_time: String,
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountAuthenticationFactors {
pub account_id: String,
pub api_key_count: u32,
pub password_count: u32,
pub verified_email_count: u32,
}
impl AccountAuthenticationFactors {
pub fn has_authentication_factor(&self) -> bool {
self.api_key_count > 0 || self.password_count > 0 || self.verified_email_count > 0
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoginResponse {
pub account: Account,
pub access_token: String,
pub id_token: String,
}
pub struct AccountService {
client: Client,
}
impl AccountService {
pub fn new() -> Self {
Self {
client: Client::new(),
}
}
pub async fn get_account_by_id(&self, account_id: &str) -> Result<Account> {
let payload = serde_json::json!({
"table": "Accounts",
"filters": { "id": account_id }
});
let resp = self.client
.post(format!("{BASE_URL}/authenticate/accounts/get"))
.json(&payload)
.send()
.await?;
let map: serde_json::Value = resp.json().await?;
if let Some(obj) = map.as_object().and_then(|o| o.values().next()) {
Ok(serde_json::from_value(obj.clone())?)
} else {
Err(anyhow!("No account found for id: {account_id}"))
}
}
pub async fn get_accounts(
&self,
filters: Option<serde_json::Value>,
) -> Result<Vec<Account>, reqwest::Error> {
let payload = if let Some(f) = filters {
serde_json::json!({ "filters": f })
} else {
serde_json::json!({})
};
let resp = self.client
.post(format!("{BASE_URL}/authenticate/accounts/get"))
.json(&payload)
.send()
.await?;
let map: serde_json::Value = resp.json().await?;
let mut accounts = vec![];
if let Some(obj) = map.as_object() {
for v in obj.values() {
if let Ok(a) = serde_json::from_value::<Account>(v.clone()) {
accounts.push(a);
}
}
}
Ok(accounts)
}
pub async fn get_authentication_factors(
&self,
account_id: &str,
) -> Result<AccountAuthenticationFactors, reqwest::Error> {
let url = format!("{BASE_URL}/authenticate/register/get/authentication/factors/{account_id}");
let resp = self.client.get(url).send().await?;
let data = resp.json::<AccountAuthenticationFactors>().await?;
Ok(data)
}
pub async fn update_account_name(
&self,
account_id: &str,
name: &str,
) -> Result<(), reqwest::Error> {
let payload = serde_json::json!({
"account": { "name": name },
"filters": { "id": account_id }
});
self.client
.patch(format!("{BASE_URL}/authenticate/accounts"))
.json(&payload)
.send()
.await?
.error_for_status()?;
Ok(())
}
}