Skip to main content

wechat_oa_sdk/api/
user.rs

1use serde::Deserialize;
2
3use crate::client::WeChatClient;
4use crate::error::Result;
5use crate::models::user::{
6    BatchUserInfoResponse, CreateTagResponse, Tag, TagListResponse, UserInfo, UserListResponse,
7    UsersByTagResponse,
8};
9
10#[derive(Deserialize)]
11#[allow(dead_code)]
12struct ApiResponse {
13    errcode: Option<i64>,
14    errmsg: Option<String>,
15}
16
17impl WeChatClient {
18    /// Get user information by OpenID.
19    pub async fn get_user_info(&self, openid: &str, lang: Option<&str>) -> Result<UserInfo> {
20        let lang = lang.unwrap_or("zh_CN");
21        self.get("/user/info", &[("openid", openid), ("lang", lang)])
22            .await
23    }
24
25    /// Batch get user information.
26    pub async fn batch_get_user_info(
27        &self,
28        openids: &[&str],
29        lang: Option<&str>,
30    ) -> Result<BatchUserInfoResponse> {
31        let lang = lang.unwrap_or("zh_CN");
32        let user_list: Vec<_> = openids
33            .iter()
34            .map(|openid| {
35                serde_json::json!({
36                    "openid": openid,
37                    "lang": lang
38                })
39            })
40            .collect();
41
42        let body = serde_json::json!({
43            "user_list": user_list
44        });
45
46        self.post_json("/user/info/batchget", &body).await
47    }
48
49    /// Get user list (followers).
50    pub async fn get_user_list(&self, next_openid: Option<&str>) -> Result<UserListResponse> {
51        let params: Vec<(&str, &str)> = match next_openid {
52            Some(openid) => vec![("next_openid", openid)],
53            None => vec![],
54        };
55        self.get("/user/get", &params).await
56    }
57
58    /// Set user remark.
59    pub async fn set_user_remark(&self, openid: &str, remark: &str) -> Result<()> {
60        let body = serde_json::json!({
61            "openid": openid,
62            "remark": remark
63        });
64        let _: ApiResponse = self.post_json("/user/info/updateremark", &body).await?;
65        Ok(())
66    }
67
68    // ========== Tag Management ==========
69
70    /// Create a user tag.
71    pub async fn create_tag(&self, name: &str) -> Result<Tag> {
72        let body = serde_json::json!({
73            "tag": { "name": name }
74        });
75        let resp: CreateTagResponse = self.post_json("/tags/create", &body).await?;
76        Ok(resp.tag)
77    }
78
79    /// Get all tags.
80    pub async fn get_tags(&self) -> Result<TagListResponse> {
81        self.get("/tags/get", &[]).await
82    }
83
84    /// Update a tag name.
85    pub async fn update_tag(&self, tag_id: i32, name: &str) -> Result<()> {
86        let body = serde_json::json!({
87            "tag": {
88                "id": tag_id,
89                "name": name
90            }
91        });
92        let _: ApiResponse = self.post_json("/tags/update", &body).await?;
93        Ok(())
94    }
95
96    /// Delete a tag.
97    pub async fn delete_tag(&self, tag_id: i32) -> Result<()> {
98        let body = serde_json::json!({
99            "tag": { "id": tag_id }
100        });
101        let _: ApiResponse = self.post_json("/tags/delete", &body).await?;
102        Ok(())
103    }
104
105    /// Get users with a specific tag.
106    pub async fn get_users_by_tag(
107        &self,
108        tag_id: i32,
109        next_openid: Option<&str>,
110    ) -> Result<UsersByTagResponse> {
111        let body = serde_json::json!({
112            "tagid": tag_id,
113            "next_openid": next_openid.unwrap_or("")
114        });
115        self.post_json("/user/tag/get", &body).await
116    }
117
118    /// Batch tag users.
119    pub async fn batch_tag_users(&self, openids: &[&str], tag_id: i32) -> Result<()> {
120        let body = serde_json::json!({
121            "openid_list": openids,
122            "tagid": tag_id
123        });
124        let _: ApiResponse = self.post_json("/tags/members/batchtagging", &body).await?;
125        Ok(())
126    }
127
128    /// Batch untag users.
129    pub async fn batch_untag_users(&self, openids: &[&str], tag_id: i32) -> Result<()> {
130        let body = serde_json::json!({
131            "openid_list": openids,
132            "tagid": tag_id
133        });
134        let _: ApiResponse = self
135            .post_json("/tags/members/batchuntagging", &body)
136            .await?;
137        Ok(())
138    }
139
140    /// Get tags of a user.
141    pub async fn get_user_tags(&self, openid: &str) -> Result<Vec<i32>> {
142        let body = serde_json::json!({
143            "openid": openid
144        });
145
146        #[derive(Deserialize)]
147        struct Response {
148            tagid_list: Vec<i32>,
149        }
150
151        let resp: Response = self.post_json("/tags/getidlist", &body).await?;
152        Ok(resp.tagid_list)
153    }
154}