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