1use std::collections::HashMap;
2
3use crate::DingTalk;
4use deadpool_redis::redis::cmd;
5use serde::{Deserialize, Serialize};
6use url::{form_urlencoded, Url};
7
8impl DingTalk {
9 pub fn get_redirect_url(&self, redirect_uri: String, state: Option<String>) -> String {
22 let mut url = Url::parse("https://login.dingtalk.com/oauth2/auth").unwrap();
23
24 let query = form_urlencoded::Serializer::new(String::new())
25 .append_pair("redirect_uri", &redirect_uri)
26 .append_pair("response_type", "code")
27 .append_pair("client_id", self.appid.as_ref())
28 .append_pair("scope", "openid corpid")
29 .append_pair("state", state.unwrap_or("".to_string()).as_ref())
30 .append_pair("prompt", "consent")
31 .finish();
32
33 url.set_query(Some(&query));
34
35 url.to_string()
36 }
37
38 pub async fn set_app_access_token(
59 &self,
60 code: String,
61 ) -> Result<String, Box<dyn std::error::Error>> {
62 let mut params = HashMap::new();
63 params.insert("clientId", self.appid.clone());
64 params.insert("clientSecret", self.app_secret.clone());
65 params.insert("code", code.clone());
66 params.insert("refreshToken", "".to_string());
67 params.insert("grantType", "authorization_code".to_string());
68
69 let response = self
70 .client
71 .post("https://api.dingtalk.com/v1.0/oauth2/userAccessToken")
72 .json(¶ms)
73 .send()
74 .await?;
75
76 if !response.status().is_success() {
77 return Err(format!("Failed to get access token: {}", response.status()).into());
78 }
79
80 #[derive(Serialize, Deserialize, Debug)]
81 struct AccessToken {
82 #[serde(rename = "accessToken")]
83 pub access_token: String,
84 #[serde(rename = "refreshToken")]
85 pub refresh_token: String,
86 #[serde(rename = "corpId")]
87 pub corp_id: String,
88 #[serde(rename = "expireIn")]
89 pub expire_in: i32,
90 }
91 let at = response.json::<AccessToken>().await?;
92
93 let mut rdb = self.rdb.get().await.unwrap();
94 cmd("SET")
95 .arg(&self.appid)
96 .arg(serde_json::to_string(&at)?)
97 .query_async::<()>(&mut rdb)
98 .await
99 .unwrap();
100
101 Ok(at.corp_id) }
103
104 pub async fn get_app_access_token(&self) -> Result<String, Box<dyn std::error::Error>> {
112 let mut rdb = self.rdb.get().await.unwrap();
113 let value: Option<String> = cmd("GET")
114 .arg(&self.appid)
115 .query_async(&mut rdb)
116 .await
117 .unwrap_or(None);
118
119 #[derive(Serialize, Deserialize, Debug)]
120 struct AccessToken {
121 #[serde(rename = "accessToken")]
122 pub access_token: String,
123 #[serde(rename = "refreshToken")]
124 pub refresh_token: String,
125 #[serde(rename = "corpId")]
126 pub corp_id: String,
127 #[serde(rename = "expireIn")]
128 pub expire_in: i32,
129 }
130 if let Some(bytes) = value {
131 let value: AccessToken = serde_json::from_str(&bytes).unwrap();
132 return Ok(value.access_token);
133 }
134
135 Err("Failed to get access token".into())
136 }
137}