br-wechat 0.0.23

This is an wechat
Documentation
use chrono::Local;
use json::{array, JsonValue, object};
use log::{error, info};
use crate::{WechatMethod};

#[derive(Clone)]
pub struct WeCom {
    pub appid: String,
    pub agent_id: String,
    pub secret: String,
    pub access_token: String,
    pub expires_in: i64,
}

impl WeCom {
    /// 获取访问用户身份
    pub fn getuserinfo(&mut self, code: &str) -> Result<JsonValue, String> {
        self.access_token()?;
        let url = format!("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token={}&code={}", self.access_token, code);
        let mut http = br_reqwest::Client::new();
        http.get(url.as_str());
        let res = http.send().unwrap();
        let res = res.json().unwrap();

        if res["errcode"].as_i32().unwrap() == 0 {
            let mut user_info = self.clone().get_by_userid(res["userid"].to_string().as_str())?;
            user_info["openid"] = self.clone().convert_to_openid(res["userid"].to_string().as_str())?["openid"].clone();
            Ok(user_info)
        } else {
            error!("getuserinfo: {}", res["errmsg"].as_str().unwrap());
            Err(res["errmsg"].to_string())
        }
    }

    /// 获取成员详细信息
    pub fn get_by_userid(&mut self, userid: &str) -> Result<JsonValue,String> {
        self.access_token()?;
        let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token={}&userid={}", self.access_token, userid);
        let mut http = br_reqwest::Client::new();
        http.get(url.as_str());
        let res = http.send().unwrap();
        let res = res.json().unwrap();
        let mut user_info = object! {};
        if res["errcode"].as_i32().unwrap() == 0 {
            user_info = res.clone();
        } else {
            info!("get_by_userid: {}", res["errmsg"].as_str().unwrap());
        }
        Ok(user_info)
    }

    pub fn convert_to_openid(&mut self, userid: &str) -> Result<JsonValue,String> {
        self.access_token()?;
        let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/convert_to_openid?access_token={}", self.access_token);
        let mut http = br_reqwest::Client::new();
        http.post(url.as_str());
        http.raw_json(object! {
            "userid": userid
        });
        let res = http.send().unwrap();
        let res = res.json().unwrap();
        let mut user_info = object! {};
        if res["errcode"].as_i32().unwrap() == 0 {
            user_info["userid"] = userid.into();
            user_info["openid"] = res["openid"].clone();
        } else {
            info!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
        }
        Ok(user_info)
    }

    pub fn login_link(&mut self, redirect_uri: &str, state: &str) -> String {
        let redirect_uri = urlencoding::encode(redirect_uri);
        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);
        url
    }
    pub fn get_department(&mut self) -> Result<JsonValue, String> {
        self.access_token()?;
        let url = format!("https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token={}", self.access_token);
        let mut http = br_reqwest::Client::new();
        http.get(url.as_str());
        let res = http.send().unwrap();
        let mut res = res.json().unwrap();
        let mut data = array![];

        let mut keys = object! {
            "1":""
        };
        if res["errcode"].as_i32().unwrap() == 0 {
            for item in res["department"].members_mut() {
                // let userlist = self.get_simplelist(item["id"].to_string().as_str().clone());
                if item["id"] == "1" {
                    continue;
                }
                keys[item["id"].to_string()] = item["name"].as_str().unwrap().into();
                item["sort"] = item["order"].to_string().into();
                item["org_dept"] = keys[item["parentid"].to_string()].clone();

                data.push(object! {
                    name:item["name"].clone(),
                    org_dept:item["org_dept"].clone(),
                    sort:item["sort"].clone(),
                    code:item["id"].clone(),
                }).unwrap();
            }
            Ok(data)
        } else {
            error!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
            Err(res["errmsg"].to_string())
        }
    }
    pub fn get_simplelist(&mut self, department_id: &str) -> Result<JsonValue, String> {
        self.access_token()?;
        let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/simplelist?access_token={}&department_id={}", self.access_token, department_id);

        let mut http = br_reqwest::Client::new();
        http.post(url.as_str());
        http.raw_json(object! {});
        let res = http.send().unwrap();
        let mut res = res.json().unwrap();

        let mut data = array![];
        if res["errcode"].as_i32().unwrap() == 0 {
            for item in res["userlist"].members_mut() {
                item.remove("department");
                data.push(object! {
                    name:item["name"].clone(),
                    account:item["userid"].clone()
                }).unwrap();
            }
            Ok(data)
        } else {
            error!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
            Err(res["errmsg"].to_string())
        }
    }
    pub fn get_simplelist_details(&mut self, department_id: &str) -> Result<JsonValue,String> {
        self.access_token()?;
        let url = format!("https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token={}&department_id={}", self.access_token, department_id);
        let mut http = br_reqwest::Client::new();
        http.post(url.as_str());
        http.raw_json(object! {});
        let res = http.send().unwrap();
        let mut res = res.json().unwrap();
        let mut data = array![];
        if res["errcode"].as_i32().unwrap() == 0 {
            for item in res["userlist"].members_mut() {
                data.push(object! {
                    status:item["status"].clone(),
                    position:item["position"].clone(),
                    department:item["department"].clone(),
                    name:item["name"].clone(),
                    account:item["userid"].clone()
                }).unwrap();
            }
            Ok(data)
        } else {
            error!("convert_to_openid: {}", res["errmsg"].as_str().unwrap());
            Err(res["errmsg"].to_string())
        }
    }
}

impl WechatMethod for WeCom {
    fn access_token(&mut self) -> Result<JsonValue, String> {
        let dt = Local::now();
        let timestamp = dt.timestamp_millis();
        if self.expires_in > timestamp {
            return Ok(object! {
                appid: self.appid.clone(),
                access_token: self.access_token.clone(),
                expires_in: self.expires_in
            });
        }
        let url = format!("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={}&corpsecret={}", self.appid, self.secret);
        let mut http = br_reqwest::Client::new();
        http.get(url.as_str());
        let res = match http.send() {
            Ok(e) => e,
            Err(e) => return Err(format!("Failed to get token from {}", e)),
        };
        let res = match res.json() {
            Ok(e) => e,
            Err(e) => return Err(format!("Failed to get token from {}", e)),
        };
        if res["errcode"].as_i32().unwrap() == 0 {
            self.access_token = res["access_token"].to_string();
            self.expires_in = timestamp + res["expires_in"].as_i64().unwrap();
            Ok(object! {
                appid: self.appid.clone(),
                access_token: self.access_token.clone(),
                expires_in: self.expires_in
            })
        } else {
            info!("access_token: {}", res["errmsg"].as_str().unwrap());
            Err(format!("access_token: {}", res["errmsg"].as_str().unwrap()))
        }
    }


    fn check(&mut self) -> Result<bool, String> {
        self.access_token()?;
        Ok(true)
    }

    fn login(&mut self, _code: &str) -> Result<JsonValue, String> {
        todo!()
    }

    fn getuserinfo(&mut self, _code: &str) -> Result<JsonValue, String> {
        todo!()
    }
}