use super::User;
use super::credential::Credential;
use crate::{
Result, constants, error::Error::InternalServer, response::Response,
user::credential::CredentialBuilder,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use tracing::{debug, instrument};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct UserInfo {
nickname: String,
gender: u8,
country: String,
province: String,
city: String,
avatar: String,
watermark: Watermark,
}
impl UserInfo {
pub fn nickname(&self) -> &str {
&self.nickname
}
pub fn gender(&self) -> u8 {
self.gender
}
pub fn country(&self) -> &str {
&self.country
}
pub fn province(&self) -> &str {
&self.province
}
pub fn city(&self) -> &str {
&self.city
}
pub fn avatar(&self) -> &str {
&self.avatar
}
pub fn app_id(&self) -> &str {
&self.watermark.app_id
}
pub fn timestamp(&self) -> u64 {
self.watermark.timestamp
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct UserBuilder {
#[serde(rename = "nickName")]
nickname: String,
gender: u8,
country: String,
province: String,
city: String,
#[serde(rename = "avatarUrl")]
avatar: String,
watermark: WatermarkBuilder,
}
impl UserBuilder {
pub(crate) fn build(self) -> UserInfo {
UserInfo {
nickname: self.nickname,
gender: self.gender,
country: self.country,
province: self.province,
city: self.city,
avatar: self.avatar,
watermark: self.watermark.build(),
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Contact {
phone_number: String,
pure_phone_number: String,
country_code: String,
watermark: Watermark,
}
impl Contact {
pub fn phone_number(&self) -> &str {
&self.phone_number
}
pub fn pure_phone_number(&self) -> &str {
&self.pure_phone_number
}
pub fn country_code(&self) -> &str {
&self.country_code
}
pub fn app_id(&self) -> &str {
&self.watermark.app_id
}
pub fn timestamp(&self) -> u64 {
self.watermark.timestamp
}
}
#[derive(Debug, Deserialize, Clone)]
pub(crate) struct ContactBuilder {
#[serde(rename = "phone_info")]
inner: PhoneInner,
}
impl ContactBuilder {
pub(crate) fn build(self) -> Contact {
Contact {
phone_number: self.inner.phone_number,
pure_phone_number: self.inner.pure_phone_number,
country_code: self.inner.country_code,
watermark: self.inner.watermark.build(),
}
}
}
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
struct PhoneInner {
#[serde(rename = "phoneNumber")]
phone_number: String,
#[serde(rename = "purePhoneNumber")]
pure_phone_number: String,
country_code: String,
watermark: WatermarkBuilder,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
struct Watermark {
app_id: String,
timestamp: u64,
}
#[derive(Debug, Deserialize, Clone)]
struct WatermarkBuilder {
#[serde(rename = "appid")]
app_id: String,
timestamp: u64,
}
impl WatermarkBuilder {
fn build(self) -> Watermark {
Watermark {
app_id: self.app_id,
timestamp: self.timestamp,
}
}
}
impl<'a> User<'a> {
#[instrument(skip(self, code))]
pub async fn login(&self, code: &str) -> Result<Credential> {
debug!("code: {}", code);
let mut map: HashMap<&str, &str> = HashMap::new();
let inner = self.client.inner_client();
map.insert("appid", &inner.app_id);
map.insert("secret", &inner.secret);
map.insert("js_code", code);
map.insert("grant_type", "authorization_code");
let response = inner
.client
.get(constants::AUTHENTICATION_END_POINT)
.query(&map)
.send()
.await?;
debug!("authentication response: {:#?}", response);
if response.status().is_success() {
let response = response.json::<Response<CredentialBuilder>>().await?;
let credential = response.extract()?.build();
debug!("credential: {:#?}", credential);
Ok(credential)
} else {
Err(InternalServer(response.text().await?))
}
}
pub async fn get_contact(&self, code: &str, open_id: Option<&str>) -> Result<Contact> {
debug!("code: {}, open_id: {:?}", code, open_id);
let mut query = HashMap::new();
let mut body = HashMap::new();
let client = &self.client.inner_client().client;
query.insert("access_token", self.client.token().await?);
body.insert("code", code);
if let Some(open_id) = open_id {
body.insert("openid", open_id);
}
let response = client
.post(constants::PHONE_END_POINT)
.query(&query)
.json(&body)
.send()
.await?;
debug!("response: {:#?}", response);
if response.status().is_success() {
let response = response.json::<Response<ContactBuilder>>().await?;
let builder = response.extract()?;
debug!("contact builder: {:#?}", builder);
Ok(builder.build())
} else {
Err(InternalServer(response.text().await?))
}
}
}