open_lark/service/im/v1/
chats.rs

1use reqwest::Method;
2use serde::{Deserialize, Serialize};
3
4use crate::core::{
5    api_req::ApiRequest,
6    api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
7    config::Config,
8    constants::AccessTokenType,
9    http::Transport,
10    req_option::RequestOption,
11    SDKResult,
12};
13
14pub struct ChatsService {
15    pub config: Config,
16}
17
18impl ChatsService {
19    /// 获取用户或机器人所在的群列表
20    ///
21    /// <https://open.feishu.cn/document/server-docs/im-v1/chat/list>
22    pub async fn list(
23        &self,
24        list_chat_request: ListChatRequest,
25        option: Option<RequestOption>,
26    ) -> SDKResult<BaseResponse<ListChatRespData>> {
27        let mut api_req = list_chat_request.api_req;
28        api_req.http_method = Method::GET;
29        api_req.api_path = "/open-apis/im/v1/chats".to_string();
30        api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
31
32        let api_resp = Transport::request(api_req, &self.config, option).await?;
33
34        Ok(api_resp)
35    }
36
37    pub fn list_iter(
38        &self,
39        list_chat_request: ListChatRequest,
40        option: Option<RequestOption>,
41    ) -> ListChatIterator<'_> {
42        ListChatIterator {
43            service: self,
44            request: list_chat_request,
45            option,
46            has_more: true,
47        }
48    }
49}
50
51pub struct ListChatIterator<'a> {
52    service: &'a ChatsService,
53    request: ListChatRequest,
54    option: Option<RequestOption>,
55    has_more: bool,
56}
57
58impl ListChatIterator<'_> {
59    pub async fn next(&mut self) -> Option<Vec<ListChat>> {
60        if !self.has_more {
61            return None;
62        }
63        match self
64            .service
65            .list(self.request.clone(), self.option.clone())
66            .await
67        {
68            Ok(resp) => match resp.data {
69                Some(data) => {
70                    self.has_more = data.has_more;
71                    if data.has_more {
72                        self.request
73                            .api_req
74                            .query_params
75                            .insert("page_token".to_string(), data.page_token.to_string());
76                        Some(data.items)
77                    } else if data.items.is_empty() {
78                        None
79                    } else {
80                        Some(data.items)
81                    }
82                }
83                None => None,
84            },
85            Err(_) => None,
86        }
87    }
88}
89
90#[derive(Default, Clone)]
91pub struct ListChatRequest {
92    api_req: ApiRequest,
93}
94
95impl ListChatRequest {
96    pub fn builder() -> ListChatRequestBuilder {
97        ListChatRequestBuilder::default()
98    }
99}
100
101#[derive(Default)]
102pub struct ListChatRequestBuilder {
103    request: ListChatRequest,
104}
105
106impl ListChatRequestBuilder {
107    /// 用户 ID 类型
108    pub fn user_id_type(mut self, user_id_type: impl ToString) -> Self {
109        self.request
110            .api_req
111            .query_params
112            .insert("user_id_type".to_string(), user_id_type.to_string());
113        self
114    }
115
116    /// 群组排序方式
117    pub fn sort_type(mut self, sort_type: impl ToString) -> Self {
118        self.request
119            .api_req
120            .query_params
121            .insert("sort_type".to_string(), sort_type.to_string());
122        self
123    }
124
125    /// 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的
126    /// page_token,下次遍历可采用该page_token 获取查询结果
127    ///
128    /// 示例值:dmJCRHhpd3JRbGV1VEVNRFFyTitRWDY5ZFkybmYrMEUwMUFYT0VMMWdENEtuYUhsNUxGMDIwemtvdE5ORjBNQQ==
129    pub fn page_token(mut self, page_token: impl ToString) -> Self {
130        self.request
131            .api_req
132            .query_params
133            .insert("page_token".to_string(), page_token.to_string());
134        self
135    }
136
137    /// 分页大小
138    pub fn page_size(mut self, page_size: i32) -> Self {
139        self.request
140            .api_req
141            .query_params
142            .insert("page_size".to_string(), page_size.to_string());
143        self
144    }
145
146    pub fn build(self) -> ListChatRequest {
147        self.request
148    }
149}
150
151// 应用ExecutableBuilder trait到ListChatRequestBuilder
152crate::impl_executable_builder_owned!(
153    ListChatRequestBuilder,
154    ChatsService,
155    ListChatRequest,
156    BaseResponse<ListChatRespData>,
157    list
158);
159
160#[derive(Debug, Serialize, Deserialize)]
161pub struct ListChatRespData {
162    /// chat 列表
163    pub items: Vec<ListChat>,
164    /// 分页标记,当 has_more 为 true 时,会同时返回新的 page_token,否则不返回 page_token
165    pub page_token: String,
166    /// 是否还有更多项
167    pub has_more: bool,
168}
169
170impl ApiResponseTrait for ListChatRespData {
171    fn data_format() -> ResponseFormat {
172        ResponseFormat::Data
173    }
174}
175
176/// chat 列表
177#[derive(Debug, Serialize, Deserialize)]
178pub struct ListChat {
179    /// 群组 ID
180    pub chat_id: String,
181    /// 群头像 URL
182    pub avatar: String,
183    /// 群名称
184    pub name: String,
185    /// 群描述
186    pub description: String,
187    /// 群主 ID
188    pub owner_id: String,
189    /// 群主 ID 类型
190    pub owner_id_type: String,
191    /// 是否是外部群
192    pub external: bool,
193    /// 租户Key,为租户在飞书上的唯一标识,用来换取对应的tenant_access_token,
194    /// 也可以用作租户在应用中的唯一标识
195    pub tenant_key: String,
196    /// 群状态
197    pub chat_status: String,
198}