open_lark/service/cloud_docs/comments/
batch_query.rs

1use reqwest::Method;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5    core::{
6        api_req::ApiRequest,
7        api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
8        config::Config,
9        constants::AccessTokenType,
10        endpoints::cloud_docs::*,
11        http::Transport,
12        req_option::RequestOption,
13        SDKResult,
14    },
15    impl_executable_builder_owned,
16};
17
18use super::list::Comment;
19
20/// 批量获取评论请求
21#[derive(Debug, Serialize, Default, Clone)]
22pub struct BatchQueryCommentsRequest {
23    #[serde(skip)]
24    api_request: ApiRequest,
25    /// 文档token
26    #[serde(skip)]
27    file_token: String,
28    /// 文档类型:doc、docx、sheet、bitable
29    #[serde(skip)]
30    file_type: String,
31    /// 评论ID列表
32    comment_ids: Vec<String>,
33    /// 用户ID类型
34    #[serde(skip_serializing_if = "Option::is_none")]
35    user_id_type: Option<String>,
36}
37
38impl BatchQueryCommentsRequest {
39    pub fn builder() -> BatchQueryCommentsRequestBuilder {
40        BatchQueryCommentsRequestBuilder::default()
41    }
42
43    pub fn new(
44        file_token: impl ToString,
45        file_type: impl ToString,
46        comment_ids: Vec<String>,
47    ) -> Self {
48        Self {
49            file_token: file_token.to_string(),
50            file_type: file_type.to_string(),
51            comment_ids,
52            ..Default::default()
53        }
54    }
55}
56
57#[derive(Default)]
58pub struct BatchQueryCommentsRequestBuilder {
59    request: BatchQueryCommentsRequest,
60}
61
62impl BatchQueryCommentsRequestBuilder {
63    /// 文档token
64    pub fn file_token(mut self, file_token: impl ToString) -> Self {
65        self.request.file_token = file_token.to_string();
66        self
67    }
68
69    /// 文档类型
70    pub fn file_type(mut self, file_type: impl ToString) -> Self {
71        self.request.file_type = file_type.to_string();
72        self
73    }
74
75    /// 设置为文档类型
76    pub fn with_doc_type(mut self) -> Self {
77        self.request.file_type = "doc".to_string();
78        self
79    }
80
81    /// 设置为docx类型
82    pub fn with_docx_type(mut self) -> Self {
83        self.request.file_type = "docx".to_string();
84        self
85    }
86
87    /// 设置为电子表格类型
88    pub fn with_sheet_type(mut self) -> Self {
89        self.request.file_type = "sheet".to_string();
90        self
91    }
92
93    /// 设置为多维表格类型
94    pub fn with_bitable_type(mut self) -> Self {
95        self.request.file_type = "bitable".to_string();
96        self
97    }
98
99    /// 评论ID列表
100    pub fn comment_ids(mut self, comment_ids: Vec<String>) -> Self {
101        self.request.comment_ids = comment_ids;
102        self
103    }
104
105    /// 添加单个评论ID
106    pub fn add_comment_id(mut self, comment_id: impl ToString) -> Self {
107        self.request.comment_ids.push(comment_id.to_string());
108        self
109    }
110
111    /// 批量添加评论ID
112    pub fn add_comment_ids(mut self, comment_ids: Vec<impl ToString>) -> Self {
113        for comment_id in comment_ids {
114            self.request.comment_ids.push(comment_id.to_string());
115        }
116        self
117    }
118
119    /// 用户ID类型
120    pub fn user_id_type(mut self, user_id_type: impl ToString) -> Self {
121        self.request.user_id_type = Some(user_id_type.to_string());
122        self
123    }
124
125    /// 使用OpenID
126    pub fn with_open_id(mut self) -> Self {
127        self.request.user_id_type = Some("open_id".to_string());
128        self
129    }
130
131    /// 使用UserID
132    pub fn with_user_id(mut self) -> Self {
133        self.request.user_id_type = Some("user_id".to_string());
134        self
135    }
136
137    /// 使用UnionID
138    pub fn with_union_id(mut self) -> Self {
139        self.request.user_id_type = Some("union_id".to_string());
140        self
141    }
142
143    pub fn build(mut self) -> BatchQueryCommentsRequest {
144        self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
145        self.request
146    }
147}
148
149// 应用ExecutableBuilder trait到BatchQueryCommentsRequestBuilder
150impl_executable_builder_owned!(
151    BatchQueryCommentsRequestBuilder,
152    super::CommentsService,
153    BatchQueryCommentsRequest,
154    BaseResponse<BatchQueryCommentsResponse>,
155    batch_query
156);
157
158/// 批量获取评论响应
159#[derive(Debug, Deserialize)]
160pub struct BatchQueryCommentsResponse {
161    /// 评论列表
162    pub items: Vec<Comment>,
163}
164
165impl ApiResponseTrait for BatchQueryCommentsResponse {
166    fn data_format() -> ResponseFormat {
167        ResponseFormat::Data
168    }
169}
170
171/// 批量获取评论
172pub async fn batch_query_comments(
173    request: BatchQueryCommentsRequest,
174    config: &Config,
175    option: Option<RequestOption>,
176) -> SDKResult<BaseResponse<BatchQueryCommentsResponse>> {
177    let mut api_req = request.api_request;
178    api_req.http_method = Method::POST;
179    api_req.api_path = format!(
180        "{}?file_type={}&file_token={}",
181        COMMENT_V1_COMMENTS_BATCH_QUERY, request.file_type, request.file_token
182    );
183
184    // 添加用户ID类型查询参数
185    if let Some(user_id_type) = request.user_id_type {
186        api_req.api_path = format!("{}&user_id_type={}", api_req.api_path, user_id_type);
187    }
188
189    api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
190
191    let api_resp = Transport::request(api_req, config, option).await?;
192    Ok(api_resp)
193}
194
195impl BatchQueryCommentsResponse {
196    /// 获取评论数量
197    pub fn count(&self) -> usize {
198        self.items.len()
199    }
200
201    /// 是否为空
202    pub fn is_empty(&self) -> bool {
203        self.items.is_empty()
204    }
205
206    /// 获取已解决的评论
207    pub fn solved_comments(&self) -> Vec<&Comment> {
208        self.items
209            .iter()
210            .filter(|comment| comment.is_solved)
211            .collect()
212    }
213
214    /// 获取未解决的评论
215    pub fn unsolved_comments(&self) -> Vec<&Comment> {
216        self.items
217            .iter()
218            .filter(|comment| !comment.is_solved)
219            .collect()
220    }
221
222    /// 获取全文评论
223    pub fn whole_comments(&self) -> Vec<&Comment> {
224        self.items
225            .iter()
226            .filter(|comment| comment.is_whole.unwrap_or(false))
227            .collect()
228    }
229
230    /// 获取非全文评论
231    pub fn non_whole_comments(&self) -> Vec<&Comment> {
232        self.items
233            .iter()
234            .filter(|comment| !comment.is_whole.unwrap_or(false))
235            .collect()
236    }
237
238    /// 根据用户ID筛选评论
239    pub fn comments_by_user(&self, user_id: &str) -> Vec<&Comment> {
240        self.items
241            .iter()
242            .filter(|comment| comment.user_id == user_id)
243            .collect()
244    }
245
246    /// 获取有回复的评论
247    pub fn comments_with_replies(&self) -> Vec<&Comment> {
248        self.items
249            .iter()
250            .filter(|comment| comment.has_replies())
251            .collect()
252    }
253}
254
255#[cfg(test)]
256#[allow(unused_variables, unused_unsafe)]
257mod tests {
258    use super::*;
259
260    #[test]
261    fn test_batch_query_comments_request_builder() {
262        let request = BatchQueryCommentsRequest::builder()
263            .file_token("doccnxxxxxx")
264            .with_doc_type()
265            .add_comment_id("comment1")
266            .add_comment_id("comment2")
267            .add_comment_ids(vec!["comment3", "comment4"])
268            .with_open_id()
269            .build();
270
271        assert_eq!(request.file_token, "doccnxxxxxx");
272        assert_eq!(request.file_type, "doc");
273        assert_eq!(request.comment_ids.len(), 4);
274        assert_eq!(request.comment_ids[0], "comment1");
275        assert_eq!(request.comment_ids[3], "comment4");
276        assert_eq!(request.user_id_type, Some("open_id".to_string()));
277    }
278}