wechat_minapp/
user.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3use tracing::debug;
4
5use crate::{Result, client::Client, constants, error::Error::InternalServer, response::Response};
6
7#[derive(Debug, Serialize, Deserialize, Clone)]
8pub struct User {
9    nickname: String,
10    gender: u8,
11    country: String,
12    province: String,
13    city: String,
14    avatar: String,
15    watermark: Watermark,
16}
17
18impl User {
19    pub fn nickname(&self) -> &str {
20        &self.nickname
21    }
22
23    pub fn gender(&self) -> u8 {
24        self.gender
25    }
26
27    pub fn country(&self) -> &str {
28        &self.country
29    }
30
31    pub fn province(&self) -> &str {
32        &self.province
33    }
34
35    pub fn city(&self) -> &str {
36        &self.city
37    }
38
39    pub fn avatar(&self) -> &str {
40        &self.avatar
41    }
42
43    pub fn app_id(&self) -> &str {
44        &self.watermark.app_id
45    }
46
47    pub fn timestamp(&self) -> u64 {
48        self.watermark.timestamp
49    }
50}
51
52#[derive(Debug, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub(crate) struct UserBuilder {
55    #[serde(rename = "nickName")]
56    nickname: String,
57    gender: u8,
58    country: String,
59    province: String,
60    city: String,
61    #[serde(rename = "avatarUrl")]
62    avatar: String,
63    watermark: WatermarkBuilder,
64}
65
66impl UserBuilder {
67    pub(crate) fn build(self) -> User {
68        User {
69            nickname: self.nickname,
70            gender: self.gender,
71            country: self.country,
72            province: self.province,
73            city: self.city,
74            avatar: self.avatar,
75            watermark: self.watermark.build(),
76        }
77    }
78}
79
80#[derive(Debug, Serialize, Deserialize, Clone)]
81pub struct Contact {
82    phone_number: String,
83    pure_phone_number: String,
84    country_code: String,
85    watermark: Watermark,
86}
87
88impl Contact {
89    pub fn phone_number(&self) -> &str {
90        &self.phone_number
91    }
92
93    pub fn pure_phone_number(&self) -> &str {
94        &self.pure_phone_number
95    }
96
97    pub fn country_code(&self) -> &str {
98        &self.country_code
99    }
100
101    pub fn app_id(&self) -> &str {
102        &self.watermark.app_id
103    }
104
105    pub fn timestamp(&self) -> u64 {
106        self.watermark.timestamp
107    }
108}
109
110#[derive(Debug, Deserialize, Clone)]
111pub(crate) struct ContactBuilder {
112    #[serde(rename = "phone_info")]
113    inner: PhoneInner,
114}
115
116impl ContactBuilder {
117    pub(crate) fn build(self) -> Contact {
118        Contact {
119            phone_number: self.inner.phone_number,
120            pure_phone_number: self.inner.pure_phone_number,
121            country_code: self.inner.country_code,
122            watermark: self.inner.watermark.build(),
123        }
124    }
125}
126
127#[derive(Debug, Deserialize, Clone)]
128#[serde(rename_all = "camelCase")]
129struct PhoneInner {
130    #[serde(rename = "phoneNumber")]
131    phone_number: String,
132    #[serde(rename = "purePhoneNumber")]
133    pure_phone_number: String,
134    country_code: String,
135    watermark: WatermarkBuilder,
136}
137
138#[derive(Debug, Serialize, Deserialize, Clone)]
139struct Watermark {
140    app_id: String,
141    timestamp: u64,
142}
143
144#[derive(Debug, Deserialize, Clone)]
145struct WatermarkBuilder {
146    #[serde(rename = "appid")]
147    app_id: String,
148    timestamp: u64,
149}
150
151impl WatermarkBuilder {
152    fn build(self) -> Watermark {
153        Watermark {
154            app_id: self.app_id,
155            timestamp: self.timestamp,
156        }
157    }
158}
159
160impl Client {
161    /// ```ignore
162    /// use wechat_minapp::Client;
163    ///
164    /// #[tokio::main]
165    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
166    ///     let app_id = "your app id";
167    ///     let secret = "your app secret";
168    ///     
169    ///     let client = Client::new(app_id, secret);
170    ///     let access_token = client.get_contace("code","openid").await?;
171    ///
172    ///     Ok(())
173    /// }
174    /// ```
175    ///
176    pub async fn get_contact(&self, code: &str, open_id: Option<&str>) -> Result<Contact> {
177        debug!("code: {}, open_id: {:?}", code, open_id);
178
179        let mut query = HashMap::new();
180        let mut body = HashMap::new();
181
182        query.insert("access_token", self.access_token().await?);
183        body.insert("code", code);
184
185        if let Some(open_id) = open_id {
186            body.insert("openid", open_id);
187        }
188
189        let response = self
190            .request()
191            .post(constants::PHONE_END_POINT)
192            .query(&query)
193            .json(&body)
194            .send()
195            .await?;
196
197        debug!("response: {:#?}", response);
198
199        if response.status().is_success() {
200            let response = response.json::<Response<ContactBuilder>>().await?;
201
202            let builder = response.extract()?;
203
204            debug!("contact builder: {:#?}", builder);
205
206            Ok(builder.build())
207        } else {
208            Err(InternalServer(response.text().await?))
209        }
210    }
211}