open_lark/service/cloud_docs/permission/public_v1/password/
delete.rs1use 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 endpoints::{cloud_docs::*, EndpointBuilder},
10 http::Transport,
11 query_params::QueryParams,
12 req_option::RequestOption,
13 SDKResult,
14};
15
16#[derive(Debug, Serialize, Default, Clone)]
18pub struct DeletePasswordRequest {
19 #[serde(skip)]
20 api_request: ApiRequest,
21 #[serde(skip)]
23 token: String,
24 #[serde(skip)]
26 obj_type: String,
27}
28
29impl DeletePasswordRequest {
30 pub fn builder() -> DeletePasswordRequestBuilder {
31 DeletePasswordRequestBuilder::default()
32 }
33
34 pub fn new(token: impl ToString, obj_type: impl ToString) -> Self {
35 Self {
36 token: token.to_string(),
37 obj_type: obj_type.to_string(),
38 ..Default::default()
39 }
40 }
41
42 pub fn for_doc(token: impl ToString) -> Self {
44 Self::new(token, "doc")
45 }
46
47 pub fn for_sheet(token: impl ToString) -> Self {
49 Self::new(token, "sheet")
50 }
51
52 pub fn for_bitable(token: impl ToString) -> Self {
54 Self::new(token, "bitable")
55 }
56
57 pub fn for_wiki(token: impl ToString) -> Self {
59 Self::new(token, "wiki")
60 }
61}
62
63#[derive(Default)]
64pub struct DeletePasswordRequestBuilder {
65 request: DeletePasswordRequest,
66}
67
68impl DeletePasswordRequestBuilder {
69 pub fn token(mut self, token: impl ToString) -> Self {
71 self.request.token = token.to_string();
72 self
73 }
74
75 pub fn obj_type(mut self, obj_type: impl ToString) -> Self {
77 self.request.obj_type = obj_type.to_string();
78 self
79 }
80
81 pub fn as_doc(mut self) -> Self {
83 self.request.obj_type = "doc".to_string();
84 self
85 }
86
87 pub fn as_sheet(mut self) -> Self {
89 self.request.obj_type = "sheet".to_string();
90 self
91 }
92
93 pub fn as_bitable(mut self) -> Self {
95 self.request.obj_type = "bitable".to_string();
96 self
97 }
98
99 pub fn as_wiki(mut self) -> Self {
101 self.request.obj_type = "wiki".to_string();
102 self
103 }
104
105 pub fn build(mut self) -> DeletePasswordRequest {
106 self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
107 self.request
108 }
109}
110
111#[derive(Debug, Deserialize)]
113pub struct PasswordDeletionResult {
114 pub delete_time: Option<i64>,
116 pub password_removed: bool,
118 pub previous_password_hint: Option<String>,
120 pub operation_id: Option<String>,
122}
123
124#[derive(Debug, Deserialize)]
126pub struct DeletePasswordResponse {
127 pub password_deletion: PasswordDeletionResult,
129}
130
131impl ApiResponseTrait for DeletePasswordResponse {
132 fn data_format() -> ResponseFormat {
133 ResponseFormat::Data
134 }
135}
136
137pub async fn delete_password(
139 request: DeletePasswordRequest,
140 config: &Config,
141 option: Option<RequestOption>,
142) -> SDKResult<BaseResponse<DeletePasswordResponse>> {
143 let mut api_req = request.api_request;
144 api_req.http_method = Method::DELETE;
145 api_req.api_path = EndpointBuilder::replace_param(
146 DRIVE_V1_PERMISSIONS_PUBLIC_PASSWORD,
147 "token",
148 &request.token,
149 );
150
151 api_req
153 .query_params
154 .insert(QueryParams::TYPE, request.obj_type);
155
156 api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
157
158 let api_resp = Transport::request(api_req, config, option).await?;
159 Ok(api_resp)
160}
161
162impl PasswordDeletionResult {
163 pub fn has_delete_time(&self) -> bool {
165 self.delete_time.is_some()
166 }
167
168 pub fn has_operation_id(&self) -> bool {
170 self.operation_id.is_some()
171 }
172
173 pub fn has_password_hint(&self) -> bool {
175 self.previous_password_hint.is_some()
176 }
177
178 pub fn delete_time_formatted(&self) -> Option<String> {
180 self.delete_time
181 .map(|timestamp| format!("删除时间: {timestamp}"))
182 }
183
184 pub fn is_successfully_removed(&self) -> bool {
186 self.password_removed
187 }
188
189 pub fn deletion_status(&self) -> &'static str {
191 if self.password_removed {
192 "密码保护已关闭"
193 } else {
194 "密码保护关闭失败"
195 }
196 }
197
198 pub fn deletion_summary(&self) -> String {
200 let mut info = Vec::new();
201
202 info.push(self.deletion_status().to_string());
203
204 if let Some(ref hint) = self.previous_password_hint {
205 info.push(format!("原密码: {hint}"));
206 }
207
208 if let Some(ref op_id) = self.operation_id {
209 info.push(format!("操作ID: {op_id}"));
210 }
211
212 info.join(", ")
213 }
214
215 pub fn security_impact(&self) -> &'static str {
217 if self.password_removed {
218 "文档安全级别降低,任何有链接的人都可以访问"
219 } else {
220 "密码保护仍然有效"
221 }
222 }
223
224 pub fn deletion_reasons(&self) -> Vec<String> {
226 if self.password_removed {
227 vec![
228 "不再需要密码保护".to_string(),
229 "密码管理复杂度降低".to_string(),
230 "提高访问便利性".to_string(),
231 "转为其他安全措施".to_string(),
232 ]
233 } else {
234 vec![
235 "删除操作失败".to_string(),
236 "权限不足".to_string(),
237 "系统错误".to_string(),
238 ]
239 }
240 }
241}
242
243impl DeletePasswordResponse {
244 pub fn deletion_info(&self) -> &PasswordDeletionResult {
246 &self.password_deletion
247 }
248
249 pub fn is_deleted(&self) -> bool {
251 self.password_deletion.password_removed
252 }
253
254 pub fn deletion_summary(&self) -> String {
256 self.password_deletion.deletion_summary()
257 }
258
259 pub fn security_assessment(&self) -> String {
261 format!("安全影响: {}", self.password_deletion.security_impact())
262 }
263
264 pub fn follow_up_recommendations(&self) -> Vec<String> {
266 let mut recommendations = Vec::new();
267
268 if self.is_deleted() {
269 recommendations.push("考虑其他安全措施,如限制分享范围".to_string());
270 recommendations.push("定期检查文档访问权限".to_string());
271 recommendations.push("如需要,可重新设置密码保护".to_string());
272 recommendations.push("通知相关人员密码保护已关闭".to_string());
273 } else {
274 recommendations.push("检查删除权限".to_string());
275 recommendations.push("稍后重试删除操作".to_string());
276 recommendations.push("联系管理员协助处理".to_string());
277 }
278
279 recommendations
280 }
281
282 pub fn security_warnings(&self) -> Vec<String> {
284 let mut warnings = Vec::new();
285
286 if self.is_deleted() {
287 warnings.push("⚠️ 密码保护已关闭,文档安全性降低".to_string());
288 warnings.push("⚠️ 任何获得链接的人都可以访问文档".to_string());
289 warnings.push("⚠️ 建议评估是否需要其他安全措施".to_string());
290 }
291
292 warnings
293 }
294
295 pub fn operation_log(&self) -> String {
297 let mut log_parts = Vec::new();
298
299 log_parts.push("操作: 关闭密码保护".to_string());
300 log_parts.push(format!(
301 "状态: {}",
302 self.password_deletion.deletion_status()
303 ));
304
305 if let Some(time) = self.password_deletion.delete_time_formatted() {
306 log_parts.push(time);
307 }
308
309 if let Some(ref op_id) = self.password_deletion.operation_id {
310 log_parts.push(format!("操作ID: {op_id}"));
311 }
312
313 log_parts.join(", ")
314 }
315}
316
317#[cfg(test)]
318#[allow(unused_variables, unused_unsafe)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn test_delete_password_request_builder() {
324 let request = DeletePasswordRequest::builder()
325 .token("doccnxxxxxx")
326 .as_doc()
327 .build();
328
329 assert_eq!(request.token, "doccnxxxxxx");
330 assert_eq!(request.obj_type, "doc");
331 }
332
333 #[test]
334 fn test_convenience_methods() {
335 let request = DeletePasswordRequest::for_doc("doccnxxxxxx");
336 assert_eq!(request.obj_type, "doc");
337 assert_eq!(request.token, "doccnxxxxxx");
338
339 let request = DeletePasswordRequest::for_sheet("shtcnxxxxxx");
340 assert_eq!(request.obj_type, "sheet");
341 assert_eq!(request.token, "shtcnxxxxxx");
342
343 let request = DeletePasswordRequest::for_bitable("bblcnxxxxxx");
344 assert_eq!(request.obj_type, "bitable");
345 assert_eq!(request.token, "bblcnxxxxxx");
346
347 let request = DeletePasswordRequest::for_wiki("wikicnxxxxxx");
348 assert_eq!(request.obj_type, "wiki");
349 assert_eq!(request.token, "wikicnxxxxxx");
350 }
351
352 #[test]
353 fn test_password_deletion_result_methods() {
354 let result = PasswordDeletionResult {
355 delete_time: Some(1234567890),
356 password_removed: true,
357 previous_password_hint: Some("pass****".to_string()),
358 operation_id: Some("op123456".to_string()),
359 };
360
361 assert!(result.has_delete_time());
362 assert!(result.has_operation_id());
363 assert!(result.has_password_hint());
364 assert!(result.is_successfully_removed());
365 assert_eq!(result.deletion_status(), "密码保护已关闭");
366 assert_eq!(
367 result.security_impact(),
368 "文档安全级别降低,任何有链接的人都可以访问"
369 );
370
371 let failed_result = PasswordDeletionResult {
372 delete_time: None,
373 password_removed: false,
374 previous_password_hint: None,
375 operation_id: None,
376 };
377
378 assert!(!failed_result.is_successfully_removed());
379 assert_eq!(failed_result.deletion_status(), "密码保护关闭失败");
380 assert_eq!(failed_result.security_impact(), "密码保护仍然有效");
381 }
382
383 #[test]
384 fn test_delete_password_response_methods() {
385 let response = DeletePasswordResponse {
386 password_deletion: PasswordDeletionResult {
387 delete_time: Some(1234567890),
388 password_removed: true,
389 previous_password_hint: Some("old****".to_string()),
390 operation_id: Some("op789".to_string()),
391 },
392 };
393
394 assert!(response.is_deleted());
395 let warnings = response.security_warnings();
396 assert!(!warnings.is_empty());
397 assert!(warnings.iter().any(|w| w.contains("密码保护已关闭")));
398
399 let recommendations = response.follow_up_recommendations();
400 assert!(recommendations.iter().any(|r| r.contains("其他安全措施")));
401 }
402}