1#![allow(clippy::derive_partial_eq_without_eq)]
99#![allow(clippy::too_many_arguments)]
100#![allow(clippy::nonstandard_macro_braces)]
101#![allow(clippy::large_enum_variant)]
102#![allow(clippy::tabs_in_doc_comments)]
103#![allow(missing_docs)]
104#![cfg_attr(docsrs, feature(doc_cfg))]
105
106pub mod admin_apps;
107pub mod admin_apps_approved;
108pub mod admin_apps_requests;
109pub mod admin_apps_restricted;
110pub mod admin_conversations;
111pub mod admin_conversations_ekm;
112pub mod admin_conversations_restrict_access;
113pub mod admin_emoji;
114pub mod admin_invite_requests;
115pub mod admin_invite_requests_approved;
116pub mod admin_invite_requests_denied;
117pub mod admin_teams;
118pub mod admin_teams_admins;
119pub mod admin_teams_owners;
120pub mod admin_teams_settings;
121pub mod admin_usergroups;
122pub mod admin_users;
123pub mod admin_users_session;
124pub mod api;
125pub mod apps;
126pub mod apps_event_authorizations;
127pub mod apps_permissions;
128pub mod apps_permissions_resources;
129pub mod apps_permissions_scopes;
130pub mod apps_permissions_users;
131pub mod auth;
132pub mod bots;
133pub mod calls;
134pub mod calls_participants;
135pub mod chat;
136pub mod chat_scheduled_messages;
137pub mod conversations;
138pub mod dialog;
139pub mod dnd;
140pub mod emoji;
141pub mod files;
142pub mod files_comments;
143pub mod files_remote;
144pub mod migration;
145pub mod oauth;
146pub mod oauth_v_2;
147pub mod pins;
148pub mod reactions;
149pub mod reminders;
150pub mod rtm;
151pub mod search;
152pub mod stars;
153pub mod team;
154pub mod team_profile;
155pub mod types;
156pub mod usergroups;
157pub mod usergroups_users;
158pub mod users;
159pub mod users_profile;
160#[doc(hidden)]
161pub mod utils;
162pub mod views;
163pub mod workflows;
164
165pub use reqwest::{header::HeaderMap, StatusCode};
166
167#[derive(Debug)]
168pub struct Response<T> {
169 pub status: reqwest::StatusCode,
170 pub headers: reqwest::header::HeaderMap,
171 pub body: T,
172}
173
174impl<T> Response<T> {
175 pub fn new(status: reqwest::StatusCode, headers: reqwest::header::HeaderMap, body: T) -> Self {
176 Self {
177 status,
178 headers,
179 body,
180 }
181 }
182}
183
184type ClientResult<T> = Result<T, ClientError>;
185
186use thiserror::Error;
187
188#[derive(Debug, Error)]
190pub enum ClientError {
191 #[error("Refresh AuthToken is empty")]
194 EmptyRefreshToken,
195 #[error(transparent)]
197 FromUtf8Error(#[from] std::string::FromUtf8Error),
198 #[error(transparent)]
200 UrlParserError(#[from] url::ParseError),
201 #[error(transparent)]
203 SerdeJsonError(#[from] serde_json::Error),
204 #[error(transparent)]
206 ReqwestError(#[from] reqwest::Error),
207 #[error(transparent)]
209 InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
210 #[error(transparent)]
212 ReqwestMiddleWareError(#[from] reqwest_middleware::Error),
213 #[error("HTTP Error. Code: {status}, message: {error}")]
215 HttpError {
216 status: http::StatusCode,
217 headers: reqwest::header::HeaderMap,
218 error: String,
219 },
220}
221
222pub const FALLBACK_HOST: &str = "https://slack.com/api";
223
224mod progenitor_support {
225 use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
226
227 const PATH_SET: &AsciiSet = &CONTROLS
228 .add(b' ')
229 .add(b'"')
230 .add(b'#')
231 .add(b'<')
232 .add(b'>')
233 .add(b'?')
234 .add(b'`')
235 .add(b'{')
236 .add(b'}');
237
238 #[allow(dead_code)]
239 pub(crate) fn encode_path(pc: &str) -> String {
240 utf8_percent_encode(pc, PATH_SET).to_string()
241 }
242}
243
244#[derive(Debug, Default)]
245pub(crate) struct Message {
246 pub body: Option<reqwest::Body>,
247 pub content_type: Option<String>,
248}
249
250use std::convert::TryInto;
251use std::env;
252use std::ops::Add;
253use std::sync::Arc;
254use std::time::{Duration, Instant};
255use tokio::sync::RwLock;
256
257const TOKEN_ENDPOINT: &str = "https://slack.com/api/oauth.v2.access";
258const USER_CONSENT_ENDPOINT: &str = "https://slack.com/oauth/v2/authorize";
259
260#[derive(Debug, Default, Clone)]
261pub struct RootDefaultServer {}
262
263impl RootDefaultServer {
264 pub fn default_url(&self) -> &str {
265 "https://slack.com/api"
266 }
267}
268
269#[derive(Clone)]
271pub struct Client {
272 host: String,
273 host_override: Option<String>,
274 token: Arc<RwLock<InnerToken>>,
275 client_id: String,
276 client_secret: String,
277 redirect_uri: String,
278
279 auto_refresh: bool,
280 client: reqwest_middleware::ClientWithMiddleware,
281}
282
283use schemars::JsonSchema;
284use serde::{Deserialize, Serialize};
285
286#[derive(Debug, JsonSchema, Clone, Default, Serialize, Deserialize)]
287pub struct AccessToken {
288 #[serde(
289 default,
290 skip_serializing_if = "String::is_empty",
291 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
292 )]
293 pub token_type: String,
294
295 #[serde(
296 default,
297 skip_serializing_if = "String::is_empty",
298 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
299 )]
300 pub access_token: String,
301 #[serde(default)]
302 pub expires_in: i64,
303
304 #[serde(
305 default,
306 skip_serializing_if = "String::is_empty",
307 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
308 )]
309 pub refresh_token: String,
310 #[serde(default, alias = "x_refresh_token_expires_in")]
311 pub refresh_token_expires_in: i64,
312
313 #[serde(
314 default,
315 skip_serializing_if = "String::is_empty",
316 deserialize_with = "crate::utils::deserialize_null_string::deserialize"
317 )]
318 pub scope: String,
319}
320
321const REFRESH_THRESHOLD: Duration = Duration::from_secs(60);
325
326#[derive(Debug, Clone)]
327struct InnerToken {
328 access_token: String,
329 refresh_token: String,
330 expires_at: Option<Instant>,
331}
332
333impl Client {
334 pub fn new<I, K, R, T, Q>(
340 client_id: I,
341 client_secret: K,
342 redirect_uri: R,
343 token: T,
344 refresh_token: Q,
345 ) -> Self
346 where
347 I: ToString,
348 K: ToString,
349 R: ToString,
350 T: ToString,
351 Q: ToString,
352 {
353 let retry_policy =
355 reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
356 let client = reqwest::Client::builder()
357 .redirect(reqwest::redirect::Policy::none())
358 .build();
359 match client {
360 Ok(c) => {
361 let client = reqwest_middleware::ClientBuilder::new(c)
362 .with(reqwest_tracing::TracingMiddleware::default())
364 .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
366 reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
367 |req: &reqwest::Request| req.try_clone().is_some(),
368 ))
369 .build();
370
371 let host = RootDefaultServer::default().default_url().to_string();
372
373 Client {
374 host,
375 host_override: None,
376 client_id: client_id.to_string(),
377 client_secret: client_secret.to_string(),
378 redirect_uri: redirect_uri.to_string(),
379 token: Arc::new(RwLock::new(InnerToken {
380 access_token: token.to_string(),
381 refresh_token: refresh_token.to_string(),
382 expires_at: None,
383 })),
384
385 auto_refresh: false,
386 client,
387 }
388 }
389 Err(e) => panic!("creating reqwest client failed: {:?}", e),
390 }
391 }
392
393 pub fn set_auto_access_token_refresh(&mut self, enabled: bool) -> &mut Self {
395 self.auto_refresh = enabled;
396 self
397 }
398
399 pub async fn set_expires_at(&self, expires_at: Option<Instant>) -> &Self {
405 self.token.write().await.expires_at = expires_at;
406 self
407 }
408
409 pub async fn expires_at(&self) -> Option<Instant> {
412 self.token.read().await.expires_at
413 }
414
415 pub async fn set_expires_in(&self, expires_in: i64) -> &Self {
418 self.token.write().await.expires_at = Self::compute_expires_at(expires_in);
419 self
420 }
421
422 pub async fn expires_in(&self) -> Option<Duration> {
425 self.token
426 .read()
427 .await
428 .expires_at
429 .map(|i| i.duration_since(Instant::now()))
430 }
431
432 pub async fn is_expired(&self) -> Option<bool> {
435 self.token
436 .read()
437 .await
438 .expires_at
439 .map(|expiration| expiration <= Instant::now())
440 }
441
442 fn compute_expires_at(expires_in: i64) -> Option<Instant> {
443 let seconds_valid = expires_in
444 .try_into()
445 .ok()
446 .map(Duration::from_secs)
447 .and_then(|dur| dur.checked_sub(REFRESH_THRESHOLD))
448 .or_else(|| Some(Duration::from_secs(0)));
449
450 seconds_valid.map(|seconds_valid| Instant::now().add(seconds_valid))
451 }
452
453 pub fn with_host_override<H>(&mut self, host: H) -> &mut Self
455 where
456 H: ToString,
457 {
458 self.host_override = Some(host.to_string());
459 self
460 }
461
462 pub fn remove_host_override(&mut self) -> &mut Self {
464 self.host_override = None;
465 self
466 }
467
468 pub fn get_host_override(&self) -> Option<&str> {
469 self.host_override.as_deref()
470 }
471
472 pub(crate) fn url(&self, path: &str, host: Option<&str>) -> String {
473 format!(
474 "{}{}",
475 self.get_host_override()
476 .or(host)
477 .unwrap_or(self.host.as_str()),
478 path
479 )
480 }
481
482 pub fn new_from_env<T, R>(token: T, refresh_token: R) -> Self
493 where
494 T: ToString,
495 R: ToString,
496 {
497 let client_id = env::var("SLACK_CLIENT_ID").expect("must set SLACK_CLIENT_ID");
498 let client_secret = env::var("SLACK_CLIENT_SECRET").expect("must set SLACK_CLIENT_SECRET");
499 let redirect_uri = env::var("SLACK_REDIRECT_URI").expect("must set SLACK_REDIRECT_URI");
500
501 Client::new(client_id, client_secret, redirect_uri, token, refresh_token)
502 }
503
504 pub fn user_consent_url(&self, scopes: &[String]) -> String {
507 let state = uuid::Uuid::new_v4();
508
509 let url = format!(
510 "{}?client_id={}&response_type=code&redirect_uri={}&state={}",
511 USER_CONSENT_ENDPOINT, self.client_id, self.redirect_uri, state
512 );
513
514 if scopes.is_empty() {
515 return url;
516 }
517
518 format!("{}&scope={}", url, scopes.join(" "))
520 }
521
522 pub async fn refresh_access_token(&self) -> ClientResult<AccessToken> {
525 let response = {
526 let refresh_token = &self.token.read().await.refresh_token;
527
528 if refresh_token.is_empty() {
529 return Err(ClientError::EmptyRefreshToken);
530 }
531
532 let mut headers = reqwest::header::HeaderMap::new();
533 headers.append(
534 reqwest::header::ACCEPT,
535 reqwest::header::HeaderValue::from_static("application/json"),
536 );
537
538 let params = [
539 ("grant_type", "refresh_token"),
540 ("refresh_token", refresh_token),
541 ("client_id", &self.client_id),
542 ("client_secret", &self.client_secret),
543 ("redirect_uri", &self.redirect_uri),
544 ];
545 let client = reqwest::Client::new();
546 client
547 .post(TOKEN_ENDPOINT)
548 .headers(headers)
549 .form(¶ms)
550 .basic_auth(&self.client_id, Some(&self.client_secret))
551 .send()
552 .await?
553 };
554
555 let t: AccessToken = response.json().await?;
557
558 let refresh_token = self.token.read().await.refresh_token.clone();
559
560 *self.token.write().await = InnerToken {
561 access_token: t.access_token.clone(),
562 refresh_token,
563 expires_at: Self::compute_expires_at(t.expires_in),
564 };
565
566 Ok(t)
567 }
568
569 pub async fn get_access_token(&mut self, code: &str, state: &str) -> ClientResult<AccessToken> {
572 let mut headers = reqwest::header::HeaderMap::new();
573 headers.append(
574 reqwest::header::ACCEPT,
575 reqwest::header::HeaderValue::from_static("application/json"),
576 );
577
578 let params = [
579 ("grant_type", "authorization_code"),
580 ("code", code),
581 ("client_id", &self.client_id),
582 ("client_secret", &self.client_secret),
583 ("redirect_uri", &self.redirect_uri),
584 ("state", state),
585 ];
586 let client = reqwest::Client::new();
587 let resp = client
588 .post(TOKEN_ENDPOINT)
589 .headers(headers)
590 .form(¶ms)
591 .basic_auth(&self.client_id, Some(&self.client_secret))
592 .send()
593 .await?;
594
595 let t: AccessToken = resp.json().await?;
597
598 *self.token.write().await = InnerToken {
599 access_token: t.access_token.clone(),
600 refresh_token: t.refresh_token.clone(),
601 expires_at: Self::compute_expires_at(t.expires_in),
602 };
603
604 Ok(t)
605 }
606
607 async fn url_and_auth(&self, uri: &str) -> ClientResult<(reqwest::Url, Option<String>)> {
608 let parsed_url = uri.parse::<reqwest::Url>()?;
609
610 let auth = format!("Bearer {}", self.token.read().await.access_token);
611 Ok((parsed_url, Some(auth)))
612 }
613
614 async fn make_request(
615 &self,
616 method: &reqwest::Method,
617 uri: &str,
618 message: Message,
619 ) -> ClientResult<reqwest::Request> {
620 let (url, auth) = self.url_and_auth(uri).await?;
621
622 let instance = <&Client>::clone(&self);
623
624 let mut req = instance.client.request(method.clone(), url);
625
626 req = req.header(
628 reqwest::header::ACCEPT,
629 reqwest::header::HeaderValue::from_static("application/json"),
630 );
631
632 if let Some(content_type) = &message.content_type {
633 req = req.header(
634 reqwest::header::CONTENT_TYPE,
635 reqwest::header::HeaderValue::from_str(content_type).unwrap(),
636 );
637 } else {
638 req = req.header(
639 reqwest::header::CONTENT_TYPE,
640 reqwest::header::HeaderValue::from_static("application/json"),
641 );
642 }
643
644 if let Some(auth_str) = auth {
645 req = req.header(http::header::AUTHORIZATION, &*auth_str);
646 }
647
648 if let Some(body) = message.body {
649 req = req.body(body);
650 }
651
652 Ok(req.build()?)
653 }
654
655 async fn request_raw(
656 &self,
657 method: reqwest::Method,
658 uri: &str,
659 message: Message,
660 ) -> ClientResult<reqwest::Response> {
661 if self.auto_refresh {
662 let expired = self.is_expired().await;
663
664 match expired {
665 Some(true) => {
668 self.refresh_access_token().await?;
669 }
670
671 Some(false) => (),
676
677 None => (),
685 }
686 }
687
688 let req = self.make_request(&method, uri, message).await?;
689 let resp = self.client.execute(req).await?;
690
691 Ok(resp)
692 }
693
694 async fn request<Out>(
695 &self,
696 method: reqwest::Method,
697 uri: &str,
698 message: Message,
699 ) -> ClientResult<crate::Response<Out>>
700 where
701 Out: serde::de::DeserializeOwned + 'static + Send,
702 {
703 let response = self.request_raw(method, uri, message).await?;
704
705 let status = response.status();
706 let headers = response.headers().clone();
707
708 let response_body = response.bytes().await?;
709
710 if status.is_success() {
711 log::debug!("Received successful response. Read payload.");
712 let parsed_response = if status == http::StatusCode::NO_CONTENT
713 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
714 {
715 serde_json::from_str("null")?
716 } else {
717 serde_json::from_slice::<Out>(&response_body)?
718 };
719 Ok(crate::Response::new(status, headers, parsed_response))
720 } else {
721 let error = if response_body.is_empty() {
722 ClientError::HttpError {
723 status,
724 headers,
725 error: "empty response".into(),
726 }
727 } else {
728 ClientError::HttpError {
729 status,
730 headers,
731 error: String::from_utf8_lossy(&response_body).into(),
732 }
733 };
734
735 Err(error)
736 }
737 }
738
739 async fn request_with_links<Out>(
740 &self,
741 method: http::Method,
742 uri: &str,
743 message: Message,
744 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Out>)>
745 where
746 Out: serde::de::DeserializeOwned + 'static + Send,
747 {
748 let response = self.request_raw(method, uri, message).await?;
749
750 let status = response.status();
751 let headers = response.headers().clone();
752 let link = response
753 .headers()
754 .get(http::header::LINK)
755 .and_then(|l| l.to_str().ok())
756 .and_then(|l| parse_link_header::parse(l).ok())
757 .as_ref()
758 .and_then(crate::utils::next_link);
759
760 let response_body = response.bytes().await?;
761
762 if status.is_success() {
763 log::debug!("Received successful response. Read payload.");
764
765 let parsed_response = if status == http::StatusCode::NO_CONTENT
766 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
767 {
768 serde_json::from_str("null")?
769 } else {
770 serde_json::from_slice::<Out>(&response_body)?
771 };
772 Ok((link, crate::Response::new(status, headers, parsed_response)))
773 } else {
774 let error = if response_body.is_empty() {
775 ClientError::HttpError {
776 status,
777 headers,
778 error: "empty response".into(),
779 }
780 } else {
781 ClientError::HttpError {
782 status,
783 headers,
784 error: String::from_utf8_lossy(&response_body).into(),
785 }
786 };
787 Err(error)
788 }
789 }
790
791 #[allow(dead_code)]
793 async fn post_form<Out>(
794 &self,
795 uri: &str,
796 form: reqwest::multipart::Form,
797 ) -> ClientResult<crate::Response<Out>>
798 where
799 Out: serde::de::DeserializeOwned + 'static + Send,
800 {
801 let (url, auth) = self.url_and_auth(uri).await?;
802
803 let instance = <&Client>::clone(&self);
804
805 let mut req = instance.client.request(http::Method::POST, url);
806
807 req = req.header(
809 reqwest::header::ACCEPT,
810 reqwest::header::HeaderValue::from_static("application/json"),
811 );
812
813 if let Some(auth_str) = auth {
814 req = req.header(http::header::AUTHORIZATION, &*auth_str);
815 }
816
817 req = req.multipart(form);
818
819 let response = req.send().await?;
820
821 let status = response.status();
822 let headers = response.headers().clone();
823
824 let response_body = response.bytes().await?;
825
826 if status.is_success() {
827 log::debug!("Received successful response. Read payload.");
828 let parsed_response = if status == http::StatusCode::NO_CONTENT
829 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
830 {
831 serde_json::from_str("null")?
832 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
833 let s = String::from_utf8(response_body.to_vec())?;
835 serde_json::from_value(serde_json::json!(&s))?
836 } else {
837 serde_json::from_slice::<Out>(&response_body)?
838 };
839 Ok(crate::Response::new(status, headers, parsed_response))
840 } else {
841 let error = if response_body.is_empty() {
842 ClientError::HttpError {
843 status,
844 headers,
845 error: "empty response".into(),
846 }
847 } else {
848 ClientError::HttpError {
849 status,
850 headers,
851 error: String::from_utf8_lossy(&response_body).into(),
852 }
853 };
854
855 Err(error)
856 }
857 }
858
859 #[allow(dead_code)]
861 async fn request_with_accept_mime<Out>(
862 &self,
863 method: reqwest::Method,
864 uri: &str,
865 accept_mime_type: &str,
866 ) -> ClientResult<crate::Response<Out>>
867 where
868 Out: serde::de::DeserializeOwned + 'static + Send,
869 {
870 let (url, auth) = self.url_and_auth(uri).await?;
871
872 let instance = <&Client>::clone(&self);
873
874 let mut req = instance.client.request(method, url);
875
876 req = req.header(
878 reqwest::header::ACCEPT,
879 reqwest::header::HeaderValue::from_str(accept_mime_type)?,
880 );
881
882 if let Some(auth_str) = auth {
883 req = req.header(http::header::AUTHORIZATION, &*auth_str);
884 }
885
886 let response = req.send().await?;
887
888 let status = response.status();
889 let headers = response.headers().clone();
890
891 let response_body = response.bytes().await?;
892
893 if status.is_success() {
894 log::debug!("Received successful response. Read payload.");
895 let parsed_response = if status == http::StatusCode::NO_CONTENT
896 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
897 {
898 serde_json::from_str("null")?
899 } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
900 let s = String::from_utf8(response_body.to_vec())?;
902 serde_json::from_value(serde_json::json!(&s))?
903 } else {
904 serde_json::from_slice::<Out>(&response_body)?
905 };
906 Ok(crate::Response::new(status, headers, parsed_response))
907 } else {
908 let error = if response_body.is_empty() {
909 ClientError::HttpError {
910 status,
911 headers,
912 error: "empty response".into(),
913 }
914 } else {
915 ClientError::HttpError {
916 status,
917 headers,
918 error: String::from_utf8_lossy(&response_body).into(),
919 }
920 };
921
922 Err(error)
923 }
924 }
925
926 #[allow(dead_code)]
928 async fn request_with_mime<Out>(
929 &self,
930 method: reqwest::Method,
931 uri: &str,
932 content: &[u8],
933 mime_type: &str,
934 ) -> ClientResult<crate::Response<Out>>
935 where
936 Out: serde::de::DeserializeOwned + 'static + Send,
937 {
938 let (url, auth) = self.url_and_auth(uri).await?;
939
940 let instance = <&Client>::clone(&self);
941
942 let mut req = instance.client.request(method, url);
943
944 req = req.header(
946 reqwest::header::ACCEPT,
947 reqwest::header::HeaderValue::from_static("application/json"),
948 );
949 req = req.header(
950 reqwest::header::CONTENT_TYPE,
951 reqwest::header::HeaderValue::from_bytes(mime_type.as_bytes()).unwrap(),
952 );
953 req = req.header(
955 reqwest::header::HeaderName::from_static("x-upload-content-type"),
956 reqwest::header::HeaderValue::from_static("application/octet-stream"),
957 );
958 req = req.header(
959 reqwest::header::HeaderName::from_static("x-upload-content-length"),
960 reqwest::header::HeaderValue::from_bytes(format!("{}", content.len()).as_bytes())
961 .unwrap(),
962 );
963
964 if let Some(auth_str) = auth {
965 req = req.header(http::header::AUTHORIZATION, &*auth_str);
966 }
967
968 if content.len() > 1 {
969 let b = bytes::Bytes::copy_from_slice(content);
970 req = req.body(b);
972 }
973
974 let response = req.send().await?;
975
976 let status = response.status();
977 let headers = response.headers().clone();
978
979 let response_body = response.bytes().await?;
980
981 if status.is_success() {
982 log::debug!("Received successful response. Read payload.");
983 let parsed_response = if status == http::StatusCode::NO_CONTENT
984 || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
985 {
986 serde_json::from_str("null")?
987 } else {
988 serde_json::from_slice::<Out>(&response_body)?
989 };
990 Ok(crate::Response::new(status, headers, parsed_response))
991 } else {
992 let error = if response_body.is_empty() {
993 ClientError::HttpError {
994 status,
995 headers,
996 error: "empty response".into(),
997 }
998 } else {
999 ClientError::HttpError {
1000 status,
1001 headers,
1002 error: String::from_utf8_lossy(&response_body).into(),
1003 }
1004 };
1005
1006 Err(error)
1007 }
1008 }
1009
1010 async fn request_entity<D>(
1011 &self,
1012 method: http::Method,
1013 uri: &str,
1014 message: Message,
1015 ) -> ClientResult<crate::Response<D>>
1016 where
1017 D: serde::de::DeserializeOwned + 'static + Send,
1018 {
1019 let r = self.request(method, uri, message).await?;
1020 Ok(r)
1021 }
1022
1023 #[allow(dead_code)]
1024 async fn get<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1025 where
1026 D: serde::de::DeserializeOwned + 'static + Send,
1027 {
1028 self.request_entity(http::Method::GET, uri, message).await
1029 }
1030
1031 #[allow(dead_code)]
1032 async fn get_all_pages<D>(&self, uri: &str, _message: Message) -> ClientResult<Response<Vec<D>>>
1033 where
1034 D: serde::de::DeserializeOwned + 'static + Send,
1035 {
1036 self.unfold(uri).await
1038 }
1039
1040 #[allow(dead_code)]
1042 async fn unfold<D>(&self, uri: &str) -> ClientResult<crate::Response<Vec<D>>>
1043 where
1044 D: serde::de::DeserializeOwned + 'static + Send,
1045 {
1046 let mut global_items = Vec::new();
1047 let (new_link, mut response) = self.get_pages(uri).await?;
1048 let mut link = new_link;
1049 while !response.body.is_empty() {
1050 global_items.append(&mut response.body);
1051 if let Some(url) = &link {
1053 let url = reqwest::Url::parse(&url.0)?;
1054 let (new_link, new_response) = self.get_pages_url(&url).await?;
1055 link = new_link;
1056 response = new_response;
1057 }
1058 }
1059
1060 Ok(Response::new(
1061 response.status,
1062 response.headers,
1063 global_items,
1064 ))
1065 }
1066
1067 #[allow(dead_code)]
1068 async fn get_pages<D>(
1069 &self,
1070 uri: &str,
1071 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1072 where
1073 D: serde::de::DeserializeOwned + 'static + Send,
1074 {
1075 self.request_with_links(http::Method::GET, uri, Message::default())
1076 .await
1077 }
1078
1079 #[allow(dead_code)]
1080 async fn get_pages_url<D>(
1081 &self,
1082 url: &reqwest::Url,
1083 ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
1084 where
1085 D: serde::de::DeserializeOwned + 'static + Send,
1086 {
1087 self.request_with_links(http::Method::GET, url.as_str(), Message::default())
1088 .await
1089 }
1090
1091 #[allow(dead_code)]
1092 async fn post<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1093 where
1094 D: serde::de::DeserializeOwned + 'static + Send,
1095 {
1096 self.request_entity(http::Method::POST, uri, message).await
1097 }
1098
1099 #[allow(dead_code)]
1100 async fn patch<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1101 where
1102 D: serde::de::DeserializeOwned + 'static + Send,
1103 {
1104 self.request_entity(http::Method::PATCH, uri, message).await
1105 }
1106
1107 #[allow(dead_code)]
1108 async fn put<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1109 where
1110 D: serde::de::DeserializeOwned + 'static + Send,
1111 {
1112 self.request_entity(http::Method::PUT, uri, message).await
1113 }
1114
1115 #[allow(dead_code)]
1116 async fn delete<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
1117 where
1118 D: serde::de::DeserializeOwned + 'static + Send,
1119 {
1120 self.request_entity(http::Method::DELETE, uri, message)
1121 .await
1122 }
1123
1124 pub fn admin_apps(&self) -> admin_apps::AdminApps {
1125 admin_apps::AdminApps::new(self.clone())
1126 }
1127
1128 pub fn admin_apps_approved(&self) -> admin_apps_approved::AdminAppsApproved {
1129 admin_apps_approved::AdminAppsApproved::new(self.clone())
1130 }
1131
1132 pub fn admin_apps_requests(&self) -> admin_apps_requests::AdminAppsRequests {
1133 admin_apps_requests::AdminAppsRequests::new(self.clone())
1134 }
1135
1136 pub fn admin_apps_restricted(&self) -> admin_apps_restricted::AdminAppsRestricted {
1137 admin_apps_restricted::AdminAppsRestricted::new(self.clone())
1138 }
1139
1140 pub fn admin_conversations(&self) -> admin_conversations::AdminConversations {
1141 admin_conversations::AdminConversations::new(self.clone())
1142 }
1143
1144 pub fn admin_conversations_ekm(&self) -> admin_conversations_ekm::AdminConversationsEkm {
1145 admin_conversations_ekm::AdminConversationsEkm::new(self.clone())
1146 }
1147
1148 pub fn admin_conversations_restrict_access(
1149 &self,
1150 ) -> admin_conversations_restrict_access::AdminConversationsRestrictAccess {
1151 admin_conversations_restrict_access::AdminConversationsRestrictAccess::new(self.clone())
1152 }
1153
1154 pub fn admin_emoji(&self) -> admin_emoji::AdminEmoji {
1155 admin_emoji::AdminEmoji::new(self.clone())
1156 }
1157
1158 pub fn admin_invite_requests(&self) -> admin_invite_requests::AdminInviteRequests {
1159 admin_invite_requests::AdminInviteRequests::new(self.clone())
1160 }
1161
1162 pub fn admin_invite_requests_approved(
1163 &self,
1164 ) -> admin_invite_requests_approved::AdminInviteRequestsApproved {
1165 admin_invite_requests_approved::AdminInviteRequestsApproved::new(self.clone())
1166 }
1167
1168 pub fn admin_invite_requests_denied(
1169 &self,
1170 ) -> admin_invite_requests_denied::AdminInviteRequestsDenied {
1171 admin_invite_requests_denied::AdminInviteRequestsDenied::new(self.clone())
1172 }
1173
1174 pub fn admin_teams(&self) -> admin_teams::AdminTeams {
1175 admin_teams::AdminTeams::new(self.clone())
1176 }
1177
1178 pub fn admin_teams_admins(&self) -> admin_teams_admins::AdminTeamsAdmins {
1179 admin_teams_admins::AdminTeamsAdmins::new(self.clone())
1180 }
1181
1182 pub fn admin_teams_owners(&self) -> admin_teams_owners::AdminTeamsOwners {
1183 admin_teams_owners::AdminTeamsOwners::new(self.clone())
1184 }
1185
1186 pub fn admin_teams_settings(&self) -> admin_teams_settings::AdminTeamsSettings {
1187 admin_teams_settings::AdminTeamsSettings::new(self.clone())
1188 }
1189
1190 pub fn admin_usergroups(&self) -> admin_usergroups::AdminUsergroups {
1191 admin_usergroups::AdminUsergroups::new(self.clone())
1192 }
1193
1194 pub fn admin_users(&self) -> admin_users::AdminUsers {
1195 admin_users::AdminUsers::new(self.clone())
1196 }
1197
1198 pub fn admin_users_session(&self) -> admin_users_session::AdminUsersSession {
1199 admin_users_session::AdminUsersSession::new(self.clone())
1200 }
1201
1202 pub fn api(&self) -> api::Api {
1203 api::Api::new(self.clone())
1204 }
1205
1206 pub fn apps(&self) -> apps::Apps {
1207 apps::Apps::new(self.clone())
1208 }
1209
1210 pub fn apps_event_authorizations(&self) -> apps_event_authorizations::AppsEventAuthorizations {
1211 apps_event_authorizations::AppsEventAuthorizations::new(self.clone())
1212 }
1213
1214 pub fn apps_permissions(&self) -> apps_permissions::AppsPermissions {
1215 apps_permissions::AppsPermissions::new(self.clone())
1216 }
1217
1218 pub fn apps_permissions_resources(
1219 &self,
1220 ) -> apps_permissions_resources::AppsPermissionsResources {
1221 apps_permissions_resources::AppsPermissionsResources::new(self.clone())
1222 }
1223
1224 pub fn apps_permissions_scopes(&self) -> apps_permissions_scopes::AppsPermissionsScopes {
1225 apps_permissions_scopes::AppsPermissionsScopes::new(self.clone())
1226 }
1227
1228 pub fn apps_permissions_users(&self) -> apps_permissions_users::AppsPermissionsUsers {
1229 apps_permissions_users::AppsPermissionsUsers::new(self.clone())
1230 }
1231
1232 pub fn auth(&self) -> auth::Auth {
1233 auth::Auth::new(self.clone())
1234 }
1235
1236 pub fn bots(&self) -> bots::Bots {
1237 bots::Bots::new(self.clone())
1238 }
1239
1240 pub fn calls(&self) -> calls::Calls {
1241 calls::Calls::new(self.clone())
1242 }
1243
1244 pub fn calls_participants(&self) -> calls_participants::CallsParticipants {
1245 calls_participants::CallsParticipants::new(self.clone())
1246 }
1247
1248 pub fn chat(&self) -> chat::Chat {
1249 chat::Chat::new(self.clone())
1250 }
1251
1252 pub fn chat_scheduled_messages(&self) -> chat_scheduled_messages::ChatScheduledMessages {
1253 chat_scheduled_messages::ChatScheduledMessages::new(self.clone())
1254 }
1255
1256 pub fn conversations(&self) -> conversations::Conversations {
1257 conversations::Conversations::new(self.clone())
1258 }
1259
1260 pub fn dialog(&self) -> dialog::Dialog {
1261 dialog::Dialog::new(self.clone())
1262 }
1263
1264 pub fn dnd(&self) -> dnd::Dnd {
1265 dnd::Dnd::new(self.clone())
1266 }
1267
1268 pub fn emoji(&self) -> emoji::Emoji {
1269 emoji::Emoji::new(self.clone())
1270 }
1271
1272 pub fn files(&self) -> files::Files {
1273 files::Files::new(self.clone())
1274 }
1275
1276 pub fn files_comments(&self) -> files_comments::FilesComments {
1277 files_comments::FilesComments::new(self.clone())
1278 }
1279
1280 pub fn files_remote(&self) -> files_remote::FilesRemote {
1281 files_remote::FilesRemote::new(self.clone())
1282 }
1283
1284 pub fn migration(&self) -> migration::Migration {
1285 migration::Migration::new(self.clone())
1286 }
1287
1288 pub fn oauth(&self) -> oauth::Oauth {
1289 oauth::Oauth::new(self.clone())
1290 }
1291
1292 pub fn oauth_v_2(&self) -> oauth_v_2::OauthV2 {
1293 oauth_v_2::OauthV2::new(self.clone())
1294 }
1295
1296 pub fn pins(&self) -> pins::Pins {
1297 pins::Pins::new(self.clone())
1298 }
1299
1300 pub fn reactions(&self) -> reactions::Reactions {
1301 reactions::Reactions::new(self.clone())
1302 }
1303
1304 pub fn reminders(&self) -> reminders::Reminders {
1305 reminders::Reminders::new(self.clone())
1306 }
1307
1308 pub fn rtm(&self) -> rtm::Rtm {
1309 rtm::Rtm::new(self.clone())
1310 }
1311
1312 pub fn search(&self) -> search::Search {
1313 search::Search::new(self.clone())
1314 }
1315
1316 pub fn stars(&self) -> stars::Stars {
1317 stars::Stars::new(self.clone())
1318 }
1319
1320 pub fn team(&self) -> team::Team {
1321 team::Team::new(self.clone())
1322 }
1323
1324 pub fn team_profile(&self) -> team_profile::TeamProfile {
1325 team_profile::TeamProfile::new(self.clone())
1326 }
1327
1328 pub fn usergroups(&self) -> usergroups::Usergroups {
1329 usergroups::Usergroups::new(self.clone())
1330 }
1331
1332 pub fn usergroups_users(&self) -> usergroups_users::UsergroupsUsers {
1333 usergroups_users::UsergroupsUsers::new(self.clone())
1334 }
1335
1336 pub fn users(&self) -> users::Users {
1337 users::Users::new(self.clone())
1338 }
1339
1340 pub fn users_profile(&self) -> users_profile::UsersProfile {
1341 users_profile::UsersProfile::new(self.clone())
1342 }
1343
1344 pub fn views(&self) -> views::Views {
1345 views::Views::new(self.clone())
1346 }
1347
1348 pub fn workflows(&self) -> workflows::Workflows {
1349 workflows::Workflows::new(self.clone())
1350 }
1351}