use super::User;
use super::credential::Credential;
use crate::{
Result, constants, error::Error::InternalServer, response::Response,
user::credential::CredentialBuilder, utils::build_request,
};
use http::Method;
use serde::{Deserialize, Serialize};
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 User {
#[instrument(skip(self, code))]
pub async fn login(&self, code: &str) -> Result<Credential> {
debug!("code: {}", code);
let config = self.client.app_config();
let query = serde_json::json!({
"appid": &config.app_id,
"secret":&config.secret,
"js_code": code,
"grant_type": "authorization_code"
});
let request = build_request(
constants::AUTHENTICATION_END_POINT,
Method::GET,
None,
Some(query),
None,
)?;
let client = &self.client.client;
let response = client.execute(request).await?;
debug!("authentication response: {:#?}", &response);
if response.status().is_success() {
let (_parts, body) = response.into_parts();
let json = serde_json::from_slice::<Response<CredentialBuilder>>(&body.to_vec())?;
let credential = json.extract()?.build();
debug!("credential: {:#?}", credential);
Ok(credential)
} else {
let (_parts, body) = response.into_parts();
let message = String::from_utf8_lossy(&body.to_vec()).to_string();
Err(InternalServer(message))
}
}
pub async fn get_contact(&self, code: &str, open_id: Option<&str>) -> Result<Contact> {
debug!("code: {}, open_id: {:?}", code, open_id);
let query = serde_json::json!({
"access_token":self.client.token().await?
});
let mut body = serde_json::json!({
"code":code
});
if let Some(open_id) = open_id {
body.as_object_mut()
.unwrap()
.insert("openid".to_string(), serde_json::json!(open_id));
}
let request = build_request(
constants::PHONE_END_POINT,
Method::POST,
None,
Some(query),
Some(body),
)?;
let client = &self.client.client;
let response = client.execute(request).await?;
debug!("authentication response: {:#?}", &response);
if response.status().is_success() {
let (_parts, body) = response.into_parts();
let json = serde_json::from_slice::<Response<ContactBuilder>>(&body.to_vec())?;
let builder = json.extract()?;
debug!("contact builder: {:#?}", builder);
Ok(builder.build())
} else {
let (_parts, body) = response.into_parts();
let message = String::from_utf8_lossy(&body.to_vec()).to_string();
Err(InternalServer(message))
}
}
}