use crate::{
app::cache::{Cache, USERS_ME_DATA_KEY, USERS_ME_DATA_TTL},
client::{TokensStore, authentication::AuthenticationHttpClient, users::UsersHttpClient},
models::{
auth::device::GetAuthDeviceResponse,
error::WayclipError,
users::{UsersLimitResponse, UsersResponse},
},
settings::{DEFAULT_TIME_FORMAT, UserSettings},
};
use chrono::Local;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
pub struct Users;
impl Users {
pub async fn logout() -> Result<(), WayclipError> {
let settings = UserSettings::load()?;
let mut auth_client = AuthenticationHttpClient::new(settings.api.url)?;
auth_client.logout().await
}
pub async fn init() -> Result<GetAuthDeviceResponse, WayclipError> {
let settings = UserSettings::load()?;
let mut auth_client = AuthenticationHttpClient::new(settings.api.url)?;
auth_client.init().await
}
pub async fn poll(interval_s: u32, device_code: String) -> Result<TokensStore, WayclipError> {
let settings = UserSettings::load()?;
let mut auth_client = AuthenticationHttpClient::new(settings.api.url)?;
auth_client.poll(interval_s, device_code).await
}
pub async fn get_me() -> Result<UsersResponse, WayclipError> {
let mut cache: Cache<UsersResponse> = Cache::init().await?;
match cache.get_item(USERS_ME_DATA_KEY.to_string()).await? {
Some(item) => Ok(item),
None => {
let settings = UserSettings::load()?;
let mut users_client = UsersHttpClient::new(settings.api.url)?;
let users_response = users_client.me().await?;
cache
.insert_item(
USERS_ME_DATA_KEY.to_string(),
users_response.clone(),
USERS_ME_DATA_TTL,
)
.await?;
Ok(users_response)
}
}
}
pub async fn get_limit() -> Result<UsersLimitResponse, WayclipError> {
let settings = UserSettings::load()?;
let mut users_client = UsersHttpClient::new(settings.api.url)?;
users_client.limit().await
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UsersInfo {
user: UsersResponse,
limit: UsersLimitResponse,
}
impl Display for UsersInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "Username: {}", self.user.username)?;
writeln!(f, "User ID: {}", self.user.user_id)?;
writeln!(f, "Email: {}", self.user.email)?;
writeln!(f, "Language: {}", self.user.language)?;
writeln!(f, "Location: {}", self.user.location)?;
let created_local = self.user.created_at.with_timezone(&Local);
writeln!(f, "Created: {}", created_local.format(DEFAULT_TIME_FORMAT))?;
if let Some(verified_at) = self.user.verified_at {
let verified_local = verified_at.with_timezone(&Local);
writeln!(
f,
"Verified: {}",
verified_local.format(DEFAULT_TIME_FORMAT)
)?;
} else {
writeln!(f, "Verified: No")?;
}
writeln!(f, "Avatar: {}", self.user.avatar_url)?;
if let Some(banned_at) = self.user.banned_at {
let banned_local = banned_at.with_timezone(&Local);
writeln!(f, "Banned: {}", banned_local.format(DEFAULT_TIME_FORMAT))?;
}
writeln!(f, "\nStorage & Limits:")?;
writeln!(f, " Tier: {}", self.limit.limit_name)?;
if let Some(ref desc) = self.limit.limit_description {
writeln!(f, " Description: {}", desc)?;
}
let percentage = if self.limit.limit_mb > 0 {
(self.limit.used_mb as f64 / self.limit.limit_mb as f64) * 100.0
} else {
0.0
};
writeln!(
f,
" Usage: {}MB / {}MB ({:.1}%)",
self.limit.used_mb, self.limit.limit_mb, percentage
)?;
Ok(())
}
}
impl From<(UsersResponse, UsersLimitResponse)> for UsersInfo {
fn from((user, limit): (UsersResponse, UsersLimitResponse)) -> Self {
Self { user, limit }
}
}
impl From<(&UsersResponse, &UsersLimitResponse)> for UsersInfo {
fn from((user, limit): (&UsersResponse, &UsersLimitResponse)) -> Self {
Self {
user: user.clone(),
limit: limit.clone(),
}
}
}