1use super::User;
2use super::credential::Credential;
3use crate::{
4 Result, constants, error::Error::InternalServer, response::Response,
5 user::credential::CredentialBuilder, utils::build_request,
6};
7use http::Method;
8use serde::{Deserialize, Serialize};
9use tracing::{debug, instrument};
10
11#[derive(Debug, Serialize, Deserialize, Clone)]
52pub struct UserInfo {
53 nickname: String,
54 gender: u8,
55 country: String,
56 province: String,
57 city: String,
58 avatar: String,
59 watermark: Watermark,
60}
61
62impl UserInfo {
63 pub fn nickname(&self) -> &str {
64 &self.nickname
65 }
66
67 pub fn gender(&self) -> u8 {
68 self.gender
69 }
70
71 pub fn country(&self) -> &str {
72 &self.country
73 }
74
75 pub fn province(&self) -> &str {
76 &self.province
77 }
78
79 pub fn city(&self) -> &str {
80 &self.city
81 }
82
83 pub fn avatar(&self) -> &str {
84 &self.avatar
85 }
86
87 pub fn app_id(&self) -> &str {
88 &self.watermark.app_id
89 }
90
91 pub fn timestamp(&self) -> u64 {
92 self.watermark.timestamp
93 }
94}
95
96#[derive(Debug, Deserialize)]
97#[serde(rename_all = "camelCase")]
98pub(crate) struct UserBuilder {
99 #[serde(rename = "nickName")]
100 nickname: String,
101 gender: u8,
102 country: String,
103 province: String,
104 city: String,
105 #[serde(rename = "avatarUrl")]
106 avatar: String,
107 watermark: WatermarkBuilder,
108}
109
110impl UserBuilder {
111 pub(crate) fn build(self) -> UserInfo {
112 UserInfo {
113 nickname: self.nickname,
114 gender: self.gender,
115 country: self.country,
116 province: self.province,
117 city: self.city,
118 avatar: self.avatar,
119 watermark: self.watermark.build(),
120 }
121 }
122}
123
124#[derive(Debug, Serialize, Deserialize, Clone)]
125pub struct Contact {
126 phone_number: String,
127 pure_phone_number: String,
128 country_code: String,
129 watermark: Watermark,
130}
131
132impl Contact {
133 pub fn phone_number(&self) -> &str {
134 &self.phone_number
135 }
136
137 pub fn pure_phone_number(&self) -> &str {
138 &self.pure_phone_number
139 }
140
141 pub fn country_code(&self) -> &str {
142 &self.country_code
143 }
144
145 pub fn app_id(&self) -> &str {
146 &self.watermark.app_id
147 }
148
149 pub fn timestamp(&self) -> u64 {
150 self.watermark.timestamp
151 }
152}
153
154#[derive(Debug, Deserialize, Clone)]
155pub(crate) struct ContactBuilder {
156 #[serde(rename = "phone_info")]
157 inner: PhoneInner,
158}
159
160impl ContactBuilder {
161 pub(crate) fn build(self) -> Contact {
162 Contact {
163 phone_number: self.inner.phone_number,
164 pure_phone_number: self.inner.pure_phone_number,
165 country_code: self.inner.country_code,
166 watermark: self.inner.watermark.build(),
167 }
168 }
169}
170
171#[derive(Debug, Deserialize, Clone)]
172#[serde(rename_all = "camelCase")]
173struct PhoneInner {
174 #[serde(rename = "phoneNumber")]
175 phone_number: String,
176 #[serde(rename = "purePhoneNumber")]
177 pure_phone_number: String,
178 country_code: String,
179 watermark: WatermarkBuilder,
180}
181
182#[derive(Debug, Serialize, Deserialize, Clone)]
183struct Watermark {
184 app_id: String,
185 timestamp: u64,
186}
187
188#[derive(Debug, Deserialize, Clone)]
189struct WatermarkBuilder {
190 #[serde(rename = "appid")]
191 app_id: String,
192 timestamp: u64,
193}
194
195impl WatermarkBuilder {
196 fn build(self) -> Watermark {
197 Watermark {
198 app_id: self.app_id,
199 timestamp: self.timestamp,
200 }
201 }
202}
203
204impl User {
205 #[instrument(skip(self, code))]
246 pub async fn login(&self, code: &str) -> Result<Credential> {
247 debug!("code: {}", code);
248 let config = self.client.app_config();
249 let query = serde_json::json!({
250 "appid": &config.app_id,
251 "secret":&config.secret,
252 "js_code": code,
253 "grant_type": "authorization_code"
254 });
255 let request = build_request(
256 constants::AUTHENTICATION_END_POINT,
257 Method::GET,
258 None,
259 Some(query),
260 None,
261 )?;
262
263 let client = &self.client.client;
264
265 let response = client.execute(request).await?;
266 debug!("authentication response: {:#?}", &response);
267
268 if response.status().is_success() {
269 let (_parts, body) = response.into_parts();
270 let json = serde_json::from_slice::<Response<CredentialBuilder>>(&body.to_vec())?;
271
272 let credential = json.extract()?.build();
273
274 debug!("credential: {:#?}", credential);
275
276 Ok(credential)
277 } else {
278 let (_parts, body) = response.into_parts();
279 let message = String::from_utf8_lossy(&body.to_vec()).to_string();
280 Err(InternalServer(message))
281 }
282 }
283
284 pub async fn get_contact(&self, code: &str, open_id: Option<&str>) -> Result<Contact> {
340 debug!("code: {}, open_id: {:?}", code, open_id);
341 let query = serde_json::json!({
342 "access_token":self.client.token().await?
343 });
344
345 let mut body = serde_json::json!({
346 "code":code
347 });
348
349 if let Some(open_id) = open_id {
350 body.as_object_mut()
351 .unwrap()
352 .insert("openid".to_string(), serde_json::json!(open_id));
353 }
354
355 let request = build_request(
356 constants::PHONE_END_POINT,
357 Method::POST,
358 None,
359 Some(query),
360 Some(body),
361 )?;
362
363 let client = &self.client.client;
364
365 let response = client.execute(request).await?;
366 debug!("authentication response: {:#?}", &response);
367
368 if response.status().is_success() {
369 let (_parts, body) = response.into_parts();
370 let json = serde_json::from_slice::<Response<ContactBuilder>>(&body.to_vec())?;
371
372 let builder = json.extract()?;
373
374 debug!("contact builder: {:#?}", builder);
375
376 Ok(builder.build())
377 } else {
378 let (_parts, body) = response.into_parts();
379 let message = String::from_utf8_lossy(&body.to_vec()).to_string();
380 Err(InternalServer(message))
381 }
382 }
383}