1use chrono::Local;
2use json::{array, JsonValue, object};
3use log::{error, info};
4use crate::{WechatMethod};
5
6#[derive(Clone)]
7pub struct WeCom {
8 pub appid: String,
9 pub agent_id: String,
10 pub secret: String,
11 pub access_token: String,
12 pub expires_in: i64,
13}
14
15impl WeCom {
16 pub fn getuserinfo(&mut self, code: &str) -> Result<JsonValue, String> {
18 self.access_token()?;
19 let url = format!("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token={}&code={}", self.access_token, code);
20 let mut http = br_reqwest::Client::new();
21 http.get(url.as_str());
22 let res = http.send().unwrap();
23 let res = res.json().unwrap();
24
25 if res["errcode"].as_i32().unwrap() == 0 {
26 let mut user_info = self.clone().get_by_userid(res["userid"].to_string().as_str())?;
27 user_info["openid"] = self.clone().convert_to_openid(res["userid"].to_string().as_str())?["openid"].clone();
28 Ok(user_info)
29 } else {
30 error!("getuserinfo: {}", res["errmsg"].as_str().unwrap());
31 Err(res["errmsg"].to_string())
32 }
33 }
34
35 pub fn get_by_userid(&mut self, userid: &str) -> Result<JsonValue,String> {
37 self.access_token()?;
38 let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token={}&userid={}", self.access_token, userid);
39 let mut http = br_reqwest::Client::new();
40 http.get(url.as_str());
41 let res = http.send().unwrap();
42 let res = res.json().unwrap();
43 let mut user_info = object! {};
44 if res["errcode"].as_i32().unwrap() == 0 {
45 user_info = res.clone();
46 } else {
47 info!("get_by_userid: {}", res["errmsg"].as_str().unwrap());
48 }
49 Ok(user_info)
50 }
51
52 pub fn convert_to_openid(&mut self, userid: &str) -> Result<JsonValue,String> {
53 self.access_token()?;
54 let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid?access_token={}", self.access_token);
55 let mut http = br_reqwest::Client::new();
56 http.post(url.as_str());
57 http.raw_json(object! {
58 "userid": userid
59 });
60 let res = http.send().unwrap();
61 let res = res.json().unwrap();
62 let mut user_info = object! {};
63 if res["errcode"].as_i32().unwrap() == 0 {
64 user_info["userid"] = userid.into();
65 user_info["openid"] = res["openid"].clone();
66 } else {
67 info!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
68 }
69 Ok(user_info)
70 }
71
72 pub fn login_link(&mut self, redirect_uri: &str, state: &str) -> String {
73 let redirect_uri = urlencoding::encode(redirect_uri);
74 let url = format!("https://login.work.weixin.qq.com/wwlogin/sso/login?appid={}&redirect_uri={redirect_uri}&state={}&login_type=CorpApp&agentid={}", self.appid, state, self.agent_id);
75 url
76 }
77 pub fn get_department(&mut self) -> Result<JsonValue, String> {
78 self.access_token()?;
79 let url = format!("https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={}", self.access_token);
80 let mut http = br_reqwest::Client::new();
81 http.get(url.as_str());
82 let res = http.send().unwrap();
83 let mut res = res.json().unwrap();
84 let mut data = array![];
85
86 let mut keys = object! {
87 "1":""
88 };
89 if res["errcode"].as_i32().unwrap() == 0 {
90 for item in res["department"].members_mut() {
91 if item["id"] == "1" {
93 continue;
94 }
95 keys[item["id"].to_string()] = item["name"].as_str().unwrap().into();
96 item["sort"] = item["order"].to_string().into();
97 item["org_dept"] = keys[item["parentid"].to_string()].clone();
98
99 data.push(object! {
100 name:item["name"].clone(),
101 org_dept:item["org_dept"].clone(),
102 sort:item["sort"].clone(),
103 code:item["id"].clone(),
104 }).unwrap();
105 }
106 Ok(data)
107 } else {
108 error!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
109 Err(res["errmsg"].to_string())
110 }
111 }
112 pub fn get_simplelist(&mut self, department_id: &str) -> Result<JsonValue, String> {
113 self.access_token()?;
114 let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token={}&department_id={}", self.access_token, department_id);
115
116 let mut http = br_reqwest::Client::new();
117 http.post(url.as_str());
118 http.raw_json(object! {});
119 let res = http.send().unwrap();
120 let mut res = res.json().unwrap();
121
122 let mut data = array![];
123 if res["errcode"].as_i32().unwrap() == 0 {
124 for item in res["userlist"].members_mut() {
125 item.remove("department");
126 data.push(object! {
127 name:item["name"].clone(),
128 account:item["userid"].clone()
129 }).unwrap();
130 }
131 Ok(data)
132 } else {
133 error!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
134 Err(res["errmsg"].to_string())
135 }
136 }
137 pub fn get_simplelist_details(&mut self, department_id: &str) -> Result<JsonValue,String> {
138 self.access_token()?;
139 let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token={}&department_id={}", self.access_token, department_id);
140 let mut http = br_reqwest::Client::new();
141 http.post(url.as_str());
142 http.raw_json(object! {});
143 let res = http.send().unwrap();
144 let mut res = res.json().unwrap();
145 let mut data = array![];
146 if res["errcode"].as_i32().unwrap() == 0 {
147 for item in res["userlist"].members_mut() {
148 data.push(object! {
149 status:item["status"].clone(),
150 position:item["position"].clone(),
151 department:item["department"].clone(),
152 name:item["name"].clone(),
153 account:item["userid"].clone()
154 }).unwrap();
155 }
156 Ok(data)
157 } else {
158 error!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
159 Err(res["errmsg"].to_string())
160 }
161 }
162}
163
164impl WechatMethod for WeCom {
165 fn access_token(&mut self) -> Result<JsonValue, String> {
166 let dt = Local::now();
167 let timestamp = dt.timestamp_millis();
168 if self.expires_in > timestamp {
169 return Ok(object! {
170 appid: self.appid.clone(),
171 access_token: self.access_token.clone(),
172 expires_in: self.expires_in
173 });
174 }
175 let url = format!("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={}&corpsecret={}", self.appid, self.secret);
176 let mut http = br_reqwest::Client::new();
177 http.get(url.as_str());
178 let res = match http.send() {
179 Ok(e) => e,
180 Err(e) => return Err(format!("Failed to get token from {}", e)),
181 };
182 let res = match res.json() {
183 Ok(e) => e,
184 Err(e) => return Err(format!("Failed to get token from {}", e)),
185 };
186 if res["errcode"].as_i32().unwrap() == 0 {
187 self.access_token = res["access_token"].to_string();
188 self.expires_in = timestamp + res["expires_in"].as_i64().unwrap();
189 Ok(object! {
190 appid: self.appid.clone(),
191 access_token: self.access_token.clone(),
192 expires_in: self.expires_in
193 })
194 } else {
195 info!("access_token: {}", res["errmsg"].as_str().unwrap());
196 Err(format!("access_token: {}", res["errmsg"].as_str().unwrap()))
197 }
198 }
199
200
201 fn check(&mut self) -> Result<bool, String> {
202 self.access_token()?;
203 Ok(true)
204 }
205
206 fn login(&mut self, _code: &str) -> Result<JsonValue, String> {
207 todo!()
208 }
209
210 fn getuserinfo(&mut self, _code: &str) -> Result<JsonValue, String> {
211 todo!()
212 }
213}