open_lark/service/cloud_docs/comments/
list_replies.rs1use 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::Reply;
19
20#[derive(Debug, Serialize, Default, Clone)]
22pub struct ListRepliesRequest {
23 #[serde(skip)]
24 api_request: ApiRequest,
25 #[serde(skip)]
27 file_token: String,
28 #[serde(skip)]
30 file_type: String,
31 #[serde(skip)]
33 comment_id: String,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 page_size: Option<i32>,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 page_token: Option<String>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 user_id_type: Option<String>,
43}
44
45impl ListRepliesRequest {
46 pub fn builder() -> ListRepliesRequestBuilder {
47 ListRepliesRequestBuilder::default()
48 }
49
50 pub fn new(
51 file_token: impl ToString,
52 file_type: impl ToString,
53 comment_id: impl ToString,
54 ) -> Self {
55 Self {
56 file_token: file_token.to_string(),
57 file_type: file_type.to_string(),
58 comment_id: comment_id.to_string(),
59 ..Default::default()
60 }
61 }
62}
63
64#[derive(Default)]
65pub struct ListRepliesRequestBuilder {
66 request: ListRepliesRequest,
67}
68
69impl ListRepliesRequestBuilder {
70 pub fn file_token(mut self, file_token: impl ToString) -> Self {
72 self.request.file_token = file_token.to_string();
73 self
74 }
75
76 pub fn file_type(mut self, file_type: impl ToString) -> Self {
78 self.request.file_type = file_type.to_string();
79 self
80 }
81
82 pub fn with_doc_type(mut self) -> Self {
84 self.request.file_type = "doc".to_string();
85 self
86 }
87
88 pub fn with_docx_type(mut self) -> Self {
90 self.request.file_type = "docx".to_string();
91 self
92 }
93
94 pub fn with_sheet_type(mut self) -> Self {
96 self.request.file_type = "sheet".to_string();
97 self
98 }
99
100 pub fn with_bitable_type(mut self) -> Self {
102 self.request.file_type = "bitable".to_string();
103 self
104 }
105
106 pub fn comment_id(mut self, comment_id: impl ToString) -> Self {
108 self.request.comment_id = comment_id.to_string();
109 self
110 }
111
112 pub fn page_size(mut self, page_size: i32) -> Self {
114 self.request.page_size = Some(page_size);
115 self
116 }
117
118 pub fn page_token(mut self, page_token: impl ToString) -> Self {
120 self.request.page_token = Some(page_token.to_string());
121 self
122 }
123
124 pub fn user_id_type(mut self, user_id_type: impl ToString) -> Self {
126 self.request.user_id_type = Some(user_id_type.to_string());
127 self
128 }
129
130 pub fn with_open_id(mut self) -> Self {
132 self.request.user_id_type = Some("open_id".to_string());
133 self
134 }
135
136 pub fn with_user_id(mut self) -> Self {
138 self.request.user_id_type = Some("user_id".to_string());
139 self
140 }
141
142 pub fn with_union_id(mut self) -> Self {
144 self.request.user_id_type = Some("union_id".to_string());
145 self
146 }
147
148 pub fn build(mut self) -> ListRepliesRequest {
149 self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
150 self.request
151 }
152}
153
154impl_executable_builder_owned!(
156 ListRepliesRequestBuilder,
157 super::CommentsService,
158 ListRepliesRequest,
159 BaseResponse<ListRepliesResponse>,
160 list_replies
161);
162
163#[derive(Debug, Deserialize)]
165pub struct ListRepliesResponse {
166 pub items: Vec<Reply>,
168 pub has_more: bool,
170 pub page_token: Option<String>,
172}
173
174impl ApiResponseTrait for ListRepliesResponse {
175 fn data_format() -> ResponseFormat {
176 ResponseFormat::Data
177 }
178}
179
180pub async fn list_replies(
182 request: ListRepliesRequest,
183 config: &Config,
184 option: Option<RequestOption>,
185) -> SDKResult<BaseResponse<ListRepliesResponse>> {
186 let mut api_req = request.api_request;
187 api_req.http_method = Method::GET;
188 api_req.api_path = format!(
189 "{}?file_type={}&file_token={}",
190 COMMENT_V1_COMMENT_REPLIES.replace("{}", &request.comment_id),
191 request.file_type,
192 request.file_token
193 );
194
195 let mut query_params = Vec::new();
197 if let Some(page_size) = request.page_size {
198 query_params.push(format!("page_size={page_size}"));
199 }
200 if let Some(page_token) = request.page_token {
201 query_params.push(format!("page_token={page_token}"));
202 }
203 if let Some(user_id_type) = request.user_id_type {
204 query_params.push(format!("user_id_type={user_id_type}"));
205 }
206
207 if !query_params.is_empty() {
208 api_req.api_path = format!("{}&{}", api_req.api_path, query_params.join("&"));
209 }
210
211 api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
212
213 let api_resp = Transport::request(api_req, config, option).await?;
214 Ok(api_resp)
215}
216
217impl ListRepliesResponse {
218 pub fn count(&self) -> usize {
220 self.items.len()
221 }
222
223 pub fn is_empty(&self) -> bool {
225 self.items.is_empty()
226 }
227
228 pub fn replies_by_user(&self, user_id: &str) -> Vec<&Reply> {
230 self.items
231 .iter()
232 .filter(|reply| reply.user_id == user_id)
233 .collect()
234 }
235
236 pub fn latest_reply(&self) -> Option<&Reply> {
238 self.items.iter().max_by_key(|reply| reply.create_time)
239 }
240
241 pub fn earliest_reply(&self) -> Option<&Reply> {
243 self.items.iter().min_by_key(|reply| reply.create_time)
244 }
245
246 pub fn sorted_by_time(&self) -> Vec<&Reply> {
248 let mut replies: Vec<&Reply> = self.items.iter().collect();
249 replies.sort_by_key(|reply| reply.create_time);
250 replies
251 }
252
253 pub fn sorted_by_time_desc(&self) -> Vec<&Reply> {
255 let mut replies: Vec<&Reply> = self.items.iter().collect();
256 replies.sort_by_key(|reply| std::cmp::Reverse(reply.create_time));
257 replies
258 }
259
260 pub fn get_all_text_content(&self) -> Vec<String> {
262 self.items
263 .iter()
264 .map(|reply| reply.get_text_content())
265 .collect()
266 }
267
268 pub fn summary(&self) -> String {
270 format!(
271 "回复总数: {}, 是否有更多: {}, 最新回复时间: {}",
272 self.count(),
273 self.has_more,
274 self.latest_reply()
275 .map(|r| r.create_time.to_string())
276 .unwrap_or_else(|| "无".to_string())
277 )
278 }
279}
280
281#[cfg(test)]
282#[allow(unused_variables, unused_unsafe)]
283mod tests {
284 use super::*;
285
286 #[test]
287 fn test_list_replies_request_builder() {
288 let request = ListRepliesRequest::builder()
289 .file_token("doccnxxxxxx")
290 .with_doc_type()
291 .comment_id("comment123")
292 .page_size(20)
293 .with_open_id()
294 .build();
295
296 assert_eq!(request.file_token, "doccnxxxxxx");
297 assert_eq!(request.file_type, "doc");
298 assert_eq!(request.comment_id, "comment123");
299 assert_eq!(request.page_size, Some(20));
300 assert_eq!(request.user_id_type, Some("open_id".to_string()));
301 }
302
303 #[test]
304 fn test_list_replies_new() {
305 let request = ListRepliesRequest::new("doccnxxxxxx", "doc", "comment123");
306 assert_eq!(request.file_token, "doccnxxxxxx");
307 assert_eq!(request.file_type, "doc");
308 assert_eq!(request.comment_id, "comment123");
309 }
310}