open_lark/service/cloud_docs/comments/
update_reply.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        http::Transport,
11        req_option::RequestOption,
12        SDKResult,
13    },
14    impl_executable_builder_owned,
15};
16
17use super::list::ReplyContent;
18
19/// 更新回复的内容请求
20#[derive(Debug, Serialize, Default, Clone)]
21pub struct UpdateReplyRequest {
22    #[serde(skip)]
23    api_request: ApiRequest,
24    /// 文档token
25    #[serde(skip)]
26    file_token: String,
27    /// 文档类型:doc、docx、sheet、bitable
28    #[serde(skip)]
29    file_type: String,
30    /// 评论ID
31    #[serde(skip)]
32    comment_id: String,
33    /// 回复ID
34    #[serde(skip)]
35    reply_id: String,
36    /// 回复内容
37    content: ReplyContent,
38    /// 用户ID类型
39    #[serde(skip_serializing_if = "Option::is_none")]
40    user_id_type: Option<String>,
41}
42
43impl UpdateReplyRequest {
44    pub fn builder() -> UpdateReplyRequestBuilder {
45        UpdateReplyRequestBuilder::default()
46    }
47
48    pub fn new(
49        file_token: impl ToString,
50        file_type: impl ToString,
51        comment_id: impl ToString,
52        reply_id: impl ToString,
53        content: ReplyContent,
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            reply_id: reply_id.to_string(),
60            content,
61            ..Default::default()
62        }
63    }
64}
65
66#[derive(Default)]
67pub struct UpdateReplyRequestBuilder {
68    request: UpdateReplyRequest,
69}
70
71impl UpdateReplyRequestBuilder {
72    /// 文档token
73    pub fn file_token(mut self, file_token: impl ToString) -> Self {
74        self.request.file_token = file_token.to_string();
75        self
76    }
77
78    /// 文档类型
79    pub fn file_type(mut self, file_type: impl ToString) -> Self {
80        self.request.file_type = file_type.to_string();
81        self
82    }
83
84    /// 设置为文档类型
85    pub fn with_doc_type(mut self) -> Self {
86        self.request.file_type = "doc".to_string();
87        self
88    }
89
90    /// 设置为docx类型
91    pub fn with_docx_type(mut self) -> Self {
92        self.request.file_type = "docx".to_string();
93        self
94    }
95
96    /// 设置为电子表格类型
97    pub fn with_sheet_type(mut self) -> Self {
98        self.request.file_type = "sheet".to_string();
99        self
100    }
101
102    /// 设置为多维表格类型
103    pub fn with_bitable_type(mut self) -> Self {
104        self.request.file_type = "bitable".to_string();
105        self
106    }
107
108    /// 评论ID
109    pub fn comment_id(mut self, comment_id: impl ToString) -> Self {
110        self.request.comment_id = comment_id.to_string();
111        self
112    }
113
114    /// 回复ID
115    pub fn reply_id(mut self, reply_id: impl ToString) -> Self {
116        self.request.reply_id = reply_id.to_string();
117        self
118    }
119
120    /// 回复内容
121    pub fn content(mut self, content: ReplyContent) -> Self {
122        self.request.content = content;
123        self
124    }
125
126    /// 用户ID类型
127    pub fn user_id_type(mut self, user_id_type: impl ToString) -> Self {
128        self.request.user_id_type = Some(user_id_type.to_string());
129        self
130    }
131
132    /// 使用OpenID
133    pub fn with_open_id(mut self) -> Self {
134        self.request.user_id_type = Some("open_id".to_string());
135        self
136    }
137
138    /// 使用UserID
139    pub fn with_user_id(mut self) -> Self {
140        self.request.user_id_type = Some("user_id".to_string());
141        self
142    }
143
144    /// 使用UnionID
145    pub fn with_union_id(mut self) -> Self {
146        self.request.user_id_type = Some("union_id".to_string());
147        self
148    }
149
150    pub fn build(mut self) -> UpdateReplyRequest {
151        self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
152        self.request
153    }
154}
155
156/// 更新后的回复信息
157#[derive(Debug, Deserialize)]
158pub struct UpdatedReply {
159    /// 回复ID
160    pub reply_id: String,
161    /// 用户ID
162    pub user_id: String,
163    /// 创建时间(毫秒时间戳)
164    pub create_time: i64,
165    /// 更新时间(毫秒时间戳)
166    pub update_time: i64,
167    /// 回复内容
168    pub content: ReplyContent,
169}
170
171// 应用ExecutableBuilder trait到UpdateReplyRequestBuilder
172impl_executable_builder_owned!(
173    UpdateReplyRequestBuilder,
174    super::CommentsService,
175    UpdateReplyRequest,
176    BaseResponse<UpdateReplyResponse>,
177    update_reply
178);
179
180/// 更新回复的内容响应
181#[derive(Debug, Deserialize)]
182pub struct UpdateReplyResponse {
183    /// 更新后的回复信息
184    pub reply: UpdatedReply,
185}
186
187impl ApiResponseTrait for UpdateReplyResponse {
188    fn data_format() -> ResponseFormat {
189        ResponseFormat::Data
190    }
191}
192
193/// 更新回复的内容
194pub async fn update_reply(
195    request: UpdateReplyRequest,
196    config: &Config,
197    option: Option<RequestOption>,
198) -> SDKResult<BaseResponse<UpdateReplyResponse>> {
199    let mut api_req = request.api_request;
200    api_req.http_method = Method::PUT;
201    api_req.api_path = format!(
202        "/open-apis/comment/v1/comments/{}/replies/{}?file_type={}&file_token={}",
203        request.comment_id, request.reply_id, request.file_type, request.file_token
204    );
205
206    // 添加用户ID类型查询参数
207    if let Some(user_id_type) = request.user_id_type {
208        api_req.api_path = format!("{}&user_id_type={}", api_req.api_path, user_id_type);
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 UpdatedReply {
218    /// 获取回复的文本内容
219    pub fn get_text_content(&self) -> String {
220        self.content
221            .elements
222            .iter()
223            .filter_map(|element| {
224                element
225                    .text_run
226                    .as_ref()
227                    .map(|text_run| text_run.text.clone())
228            })
229            .collect::<Vec<_>>()
230            .join("")
231    }
232
233    /// 是否已更新
234    pub fn is_updated(&self) -> bool {
235        self.update_time > self.create_time
236    }
237
238    /// 获取更新时间与创建时间的差值(毫秒)
239    pub fn time_since_creation(&self) -> i64 {
240        self.update_time - self.create_time
241    }
242
243    /// 获取更新时间的格式化字符串
244    pub fn updated_at_formatted(&self) -> String {
245        format!("更新时间: {}", self.update_time)
246    }
247
248    /// 获取回复摘要信息
249    pub fn summary(&self) -> String {
250        format!(
251            "回复ID: {}, 用户: {}, 内容: {}, 更新时间: {}",
252            self.reply_id,
253            self.user_id,
254            self.get_text_content(),
255            self.update_time
256        )
257    }
258}
259
260impl UpdateReplyResponse {
261    /// 获取回复ID
262    pub fn reply_id(&self) -> &str {
263        &self.reply.reply_id
264    }
265
266    /// 获取用户ID
267    pub fn user_id(&self) -> &str {
268        &self.reply.user_id
269    }
270
271    /// 获取回复的文本内容
272    pub fn get_text_content(&self) -> String {
273        self.reply.get_text_content()
274    }
275
276    /// 是否已更新
277    pub fn is_updated(&self) -> bool {
278        self.reply.is_updated()
279    }
280
281    /// 获取创建时间
282    pub fn create_time(&self) -> i64 {
283        self.reply.create_time
284    }
285
286    /// 获取更新时间
287    pub fn update_time(&self) -> i64 {
288        self.reply.update_time
289    }
290
291    /// 获取更新摘要
292    pub fn update_summary(&self) -> String {
293        format!(
294            "回复更新成功 - ID: {}, 新内容: \"{}\"",
295            self.reply_id(),
296            self.get_text_content()
297        )
298    }
299}
300
301#[cfg(test)]
302mod tests {
303    use super::*;
304    use crate::service::comments::create::ContentBuilder;
305
306    #[test]
307    fn test_update_reply_request_builder() {
308        let content = ContentBuilder::new().add_text("更新后的回复内容").build();
309
310        let request = UpdateReplyRequest::builder()
311            .file_token("doccnxxxxxx")
312            .with_doc_type()
313            .comment_id("comment123")
314            .reply_id("reply456")
315            .content(content)
316            .with_open_id()
317            .build();
318
319        assert_eq!(request.file_token, "doccnxxxxxx");
320        assert_eq!(request.file_type, "doc");
321        assert_eq!(request.comment_id, "comment123");
322        assert_eq!(request.reply_id, "reply456");
323        assert_eq!(request.user_id_type, Some("open_id".to_string()));
324    }
325}