wechat_minapp/user/
user_info.rs1use super::User;
2use super::credential::Credential;
3use crate::{
4 Result, constants, error::Error::InternalServer, response::Response,
5 user::credential::CredentialBuilder,
6};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
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
249 let mut map: HashMap<&str, &str> = HashMap::new();
250 let inner = self.client.inner_client();
251 map.insert("appid", &inner.app_id);
252 map.insert("secret", &inner.secret);
253 map.insert("js_code", code);
254 map.insert("grant_type", "authorization_code");
255
256 let response = inner
257 .client
258 .get(constants::AUTHENTICATION_END_POINT)
259 .query(&map)
260 .send()
261 .await?;
262
263 debug!("authentication response: {:#?}", response);
264
265 if response.status().is_success() {
266 let response = response.json::<Response<CredentialBuilder>>().await?;
267
268 let credential = response.extract()?.build();
269
270 debug!("credential: {:#?}", credential);
271
272 Ok(credential)
273 } else {
274 Err(InternalServer(response.text().await?))
275 }
276 }
277
278 pub async fn get_contact(&self, code: &str, open_id: Option<&str>) -> Result<Contact> {
335 debug!("code: {}, open_id: {:?}", code, open_id);
336
337 let mut query = HashMap::new();
338 let mut body = HashMap::new();
339 let client = &self.client.inner_client().client;
340 query.insert("access_token", self.client.token().await?);
341 body.insert("code", code);
342
343 if let Some(open_id) = open_id {
344 body.insert("openid", open_id);
345 }
346
347 let response = client
348 .post(constants::PHONE_END_POINT)
349 .query(&query)
350 .json(&body)
351 .send()
352 .await?;
353
354 debug!("response: {:#?}", response);
355
356 if response.status().is_success() {
357 let response = response.json::<Response<ContactBuilder>>().await?;
358
359 let builder = response.extract()?;
360
361 debug!("contact builder: {:#?}", builder);
362
363 Ok(builder.build())
364 } else {
365 Err(InternalServer(response.text().await?))
366 }
367 }
368}