use super::Deserializer;
use crate::{
types::{Org, User, UserType},
user::Token,
};
use reqwest::Url;
use serde::de::Error;
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
struct RawOrg {
pub name: String,
pub blogger: bool,
pub school_type: u32,
pub leisure_school: u32,
pub class: String,
pub org_id: u32,
pub token_login: String,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
struct RawUser {
pub picture_url: String,
pub name: String,
pub is_of_age: bool,
pub app_key: String,
pub orgs: Vec<RawOrg>,
#[serde(rename = "type")]
pub user_type: u8,
pub user_id: u32,
}
impl Deserializer for User {
type Error = serde_json::Error;
fn deserialize(json: &str) -> Result<User, serde_json::Error> {
let raw: RawUser = serde_json::from_str(json)?;
let orgs: Vec<Org> = raw.orgs.into_iter().map(Org::from).collect();
let mut school_url = Url::parse(&orgs[0].token_login).unwrap();
let segments = school_url.clone();
school_url.set_path(segments.path_segments().unwrap().next().unwrap());
school_url.set_query(None);
school_url.set_fragment(None);
Ok(User {
school_url,
client: reqwest::Client::new(),
name: raw.name,
pictute_url: raw.picture_url,
is_of_age: raw.is_of_age,
app_key: raw.app_key,
token: None,
user_type: UserType::from_u8(raw.user_type)
.ok_or(serde_json::Error::custom("Invalid user type"))?,
id: raw.user_id,
orgs,
})
}
}
impl Token {
pub fn deserialize(json: &str) -> Result<Token, serde_json::Error> {
#[derive(Deserialize)]
struct RawToken {
#[serde(rename = "expiryDate")]
expiry_date: String,
token: String,
}
let raw_token: RawToken = serde_json::from_str(json)?;
Ok(Token {
now: || chrono::Utc::now().naive_utc(),
token: raw_token.token,
expires: chrono::NaiveDateTime::parse_from_str(
&raw_token.expiry_date,
"%Y-%m-%d %H:%M:%S%.f",
)
.map_err(serde_json::Error::custom)?,
})
}
}
impl UserType {
fn from_u8(user_type: u8) -> Option<UserType> {
match user_type {
1 => Some(UserType::Student),
2 => Some(UserType::Parent),
3 => Some(UserType::Teacher),
_ => None,
}
}
}
impl From<RawOrg> for Org {
fn from(value: RawOrg) -> Self {
Org {
id: value.org_id,
name: value.name,
blogger: value.blogger,
school_type: value.school_type,
leisure_school: value.leisure_school,
class: value.class,
token_login: value.token_login,
}
}
}