use serde::{Deserialize, Serialize};
use crate::{
error::{ApiError, check_response},
url::FirebaseUrl,
};
pub async fn get(
firebase_url: &FirebaseUrl,
id_token: &str,
) -> Result<Option<GetAccountResponse>, ApiError> {
let client = reqwest::Client::new();
let response = client
.post(&firebase_url.account_lookup_url)
.header("Content-Type", "application/json")
.json(&GetAccountPayload { id_token })
.send()
.await?;
let mut body: GetAccountResponseOuter = check_response(response).await?;
Ok(body.users.pop())
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct GetAccountPayload<'a> {
id_token: &'a str,
}
#[derive(Debug, Deserialize)]
struct GetAccountResponseOuter {
users: Vec<GetAccountResponse>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct GetAccountResponse {
pub local_id: String,
pub email: String,
pub password_hash: String,
pub email_verified: bool,
pub password_updated_at: u64,
pub provider_user_info: Vec<ProviderUserInfo>,
pub valid_since: String,
pub last_login_at: String,
pub created_at: String,
pub last_refresh_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProviderUserInfo {
pub provider_id: String,
pub federated_id: String,
pub email: String,
pub raw_id: String,
}
pub async fn update(
firebase_url: &FirebaseUrl,
id_token: &str,
email: Option<&str>,
password: Option<&str>,
return_secure_token: bool,
) -> Result<UpdateAccountResponse, ApiError> {
let client = reqwest::Client::new();
let response = client
.post(&firebase_url.account_update_url)
.header("Content-Type", "application/json")
.json(&UpdateAccountPayload {
id_token,
email,
password,
return_secure_token,
})
.send()
.await?;
check_response(response).await
}
pub async fn change_email(
firebase_url: &FirebaseUrl,
id_token: &str,
email: &str,
return_secure_token: bool,
) -> Result<UpdateAccountResponse, ApiError> {
update(
firebase_url,
id_token,
Some(email),
None,
return_secure_token,
)
.await
}
pub async fn change_password(
firebase_url: &FirebaseUrl,
id_token: &str,
password: &str,
return_secure_token: bool,
) -> Result<UpdateAccountResponse, ApiError> {
update(
firebase_url,
id_token,
None,
Some(password),
return_secure_token,
)
.await
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct UpdateAccountPayload<'a> {
id_token: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
email: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
password: Option<&'a str>,
return_secure_token: bool,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UpdateAccountResponse {
pub kind: String,
pub local_id: String,
pub email: String,
pub provider_user_info: Vec<ProviderUserInfo>,
pub password_hash: String,
pub email_verified: bool,
pub id_token: Option<String>,
pub refresh_token: Option<String>,
pub expires_in: Option<String>,
}
pub async fn send_oob_code(
firebase_url: &FirebaseUrl,
request_type: &str,
id_token: Option<&str>,
email: Option<&str>,
) -> Result<SendOobCodeResponse, ApiError> {
let client = reqwest::Client::new();
let response = client
.post(&firebase_url.account_send_oob_code_url)
.header("Content-Type", "application/json")
.json(&SendOobCodePayload {
request_type,
id_token,
email,
})
.send()
.await?;
check_response(response).await
}
pub async fn reset_password(
firebase_url: &FirebaseUrl,
email: &str,
) -> Result<SendOobCodeResponse, ApiError> {
send_oob_code(firebase_url, "PASSWORD_RESET", None, Some(email)).await
}
pub async fn verify_email(
firebase_url: &FirebaseUrl,
id_token: &str,
) -> Result<SendOobCodeResponse, ApiError> {
send_oob_code(firebase_url, "VERIFY_EMAIL", Some(id_token), None).await
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct SendOobCodePayload<'a> {
request_type: &'a str,
id_token: Option<&'a str>,
email: Option<&'a str>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SendOobCodeResponse {
pub kind: String,
pub email: String,
}