open_lark/service/cloud_docs/permission/public_v2/
patch.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 http::Transport,
10 req_option::RequestOption,
11 SDKResult,
12};
13
14#[derive(Debug, Serialize, Default, Clone)]
16pub struct PatchPermissionPublicV2Request {
17 #[serde(skip)]
18 api_request: ApiRequest,
19 #[serde(skip)]
21 token: String,
22 #[serde(skip)]
24 obj_type: String,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 link_share_setting: Option<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 allow_copy: Option<bool>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 allow_comment: Option<bool>,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 allow_save_copy: Option<bool>,
37 #[serde(skip_serializing_if = "Option::is_none")]
39 watermark_setting: Option<String>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 allow_share_partner_tenant: Option<bool>,
43 #[serde(skip_serializing_if = "Option::is_none")]
45 access_setting: Option<String>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 share_scope: Option<String>,
49 #[serde(skip_serializing_if = "Option::is_none")]
51 expire_time: Option<i64>,
52}
53
54impl PatchPermissionPublicV2Request {
55 pub fn builder() -> PatchPermissionPublicV2RequestBuilder {
56 PatchPermissionPublicV2RequestBuilder::default()
57 }
58
59 pub fn new(token: impl ToString, obj_type: impl ToString) -> Self {
60 Self {
61 token: token.to_string(),
62 obj_type: obj_type.to_string(),
63 ..Default::default()
64 }
65 }
66
67 pub fn for_doc(token: impl ToString) -> Self {
69 Self::new(token, "doc")
70 }
71
72 pub fn for_sheet(token: impl ToString) -> Self {
74 Self::new(token, "sheet")
75 }
76
77 pub fn for_bitable(token: impl ToString) -> Self {
79 Self::new(token, "bitable")
80 }
81
82 pub fn for_wiki(token: impl ToString) -> Self {
84 Self::new(token, "wiki")
85 }
86}
87
88#[derive(Default)]
89pub struct PatchPermissionPublicV2RequestBuilder {
90 request: PatchPermissionPublicV2Request,
91}
92
93impl PatchPermissionPublicV2RequestBuilder {
94 pub fn token(mut self, token: impl ToString) -> Self {
96 self.request.token = token.to_string();
97 self
98 }
99
100 pub fn obj_type(mut self, obj_type: impl ToString) -> Self {
102 self.request.obj_type = obj_type.to_string();
103 self
104 }
105
106 pub fn as_doc(mut self) -> Self {
108 self.request.obj_type = "doc".to_string();
109 self
110 }
111
112 pub fn as_sheet(mut self) -> Self {
114 self.request.obj_type = "sheet".to_string();
115 self
116 }
117
118 pub fn as_bitable(mut self) -> Self {
120 self.request.obj_type = "bitable".to_string();
121 self
122 }
123
124 pub fn as_wiki(mut self) -> Self {
126 self.request.obj_type = "wiki".to_string();
127 self
128 }
129
130 pub fn link_share_setting(mut self, setting: impl ToString) -> Self {
132 self.request.link_share_setting = Some(setting.to_string());
133 self
134 }
135
136 pub fn close_sharing(mut self) -> Self {
138 self.request.link_share_setting = Some("closed".to_string());
139 self
140 }
141
142 pub fn tenant_readable(mut self) -> Self {
144 self.request.link_share_setting = Some("tenant_readable".to_string());
145 self
146 }
147
148 pub fn tenant_editable(mut self) -> Self {
150 self.request.link_share_setting = Some("tenant_editable".to_string());
151 self
152 }
153
154 pub fn anyone_readable(mut self) -> Self {
156 self.request.link_share_setting = Some("anyone_readable".to_string());
157 self
158 }
159
160 pub fn anyone_editable(mut self) -> Self {
162 self.request.link_share_setting = Some("anyone_editable".to_string());
163 self
164 }
165
166 pub fn allow_copy(mut self, allow: bool) -> Self {
168 self.request.allow_copy = Some(allow);
169 self
170 }
171
172 pub fn enable_copy(mut self) -> Self {
174 self.request.allow_copy = Some(true);
175 self
176 }
177
178 pub fn disable_copy(mut self) -> Self {
180 self.request.allow_copy = Some(false);
181 self
182 }
183
184 pub fn allow_comment(mut self, allow: bool) -> Self {
186 self.request.allow_comment = Some(allow);
187 self
188 }
189
190 pub fn enable_comment(mut self) -> Self {
192 self.request.allow_comment = Some(true);
193 self
194 }
195
196 pub fn disable_comment(mut self) -> Self {
198 self.request.allow_comment = Some(false);
199 self
200 }
201
202 pub fn allow_save_copy(mut self, allow: bool) -> Self {
204 self.request.allow_save_copy = Some(allow);
205 self
206 }
207
208 pub fn enable_save_copy(mut self) -> Self {
210 self.request.allow_save_copy = Some(true);
211 self
212 }
213
214 pub fn disable_save_copy(mut self) -> Self {
216 self.request.allow_save_copy = Some(false);
217 self
218 }
219
220 pub fn watermark_setting(mut self, setting: impl ToString) -> Self {
222 self.request.watermark_setting = Some(setting.to_string());
223 self
224 }
225
226 pub fn enable_watermark(mut self) -> Self {
228 self.request.watermark_setting = Some("visible".to_string());
229 self
230 }
231
232 pub fn disable_watermark(mut self) -> Self {
234 self.request.watermark_setting = Some("none".to_string());
235 self
236 }
237
238 pub fn allow_share_partner_tenant(mut self, allow: bool) -> Self {
240 self.request.allow_share_partner_tenant = Some(allow);
241 self
242 }
243
244 pub fn enable_external_share(mut self) -> Self {
246 self.request.allow_share_partner_tenant = Some(true);
247 self
248 }
249
250 pub fn disable_external_share(mut self) -> Self {
252 self.request.allow_share_partner_tenant = Some(false);
253 self
254 }
255
256 pub fn access_setting(mut self, setting: impl ToString) -> Self {
258 self.request.access_setting = Some(setting.to_string());
259 self
260 }
261
262 pub fn share_scope(mut self, scope: impl ToString) -> Self {
264 self.request.share_scope = Some(scope.to_string());
265 self
266 }
267
268 pub fn expire_time(mut self, timestamp: i64) -> Self {
270 self.request.expire_time = Some(timestamp);
271 self
272 }
273
274 pub fn expire_after_seconds(mut self, seconds: i64) -> Self {
276 let expire_time = chrono::Utc::now().timestamp() + seconds;
277 self.request.expire_time = Some(expire_time);
278 self
279 }
280
281 pub fn expire_after_hours(self, hours: i64) -> Self {
283 self.expire_after_seconds(hours * 3600)
284 }
285
286 pub fn expire_after_days(self, days: i64) -> Self {
288 self.expire_after_seconds(days * 86400)
289 }
290
291 pub fn never_expire(mut self) -> Self {
293 self.request.expire_time = Some(0); self
295 }
296
297 pub fn enterprise_secure_mode(mut self) -> Self {
299 self.request.link_share_setting = Some("tenant_readable".to_string());
300 self.request.allow_copy = Some(false);
301 self.request.allow_comment = Some(false);
302 self.request.allow_save_copy = Some(false);
303 self.request.watermark_setting = Some("visible".to_string());
304 self.request.allow_share_partner_tenant = Some(false);
305 self
306 }
307
308 pub fn collaboration_mode(mut self) -> Self {
310 self.request.link_share_setting = Some("tenant_editable".to_string());
311 self.request.allow_copy = Some(true);
312 self.request.allow_comment = Some(true);
313 self.request.allow_save_copy = Some(true);
314 self.request.watermark_setting = Some("none".to_string());
315 self.request.allow_share_partner_tenant = Some(false);
316 self
317 }
318
319 pub fn public_share_mode(mut self) -> Self {
321 self.request.link_share_setting = Some("anyone_readable".to_string());
322 self.request.allow_copy = Some(false);
323 self.request.allow_comment = Some(true);
324 self.request.allow_save_copy = Some(false);
325 self.request.watermark_setting = Some("visible".to_string());
326 self.request.allow_share_partner_tenant = Some(true);
327 self
328 }
329
330 pub fn open_edit_mode(mut self) -> Self {
332 self.request.link_share_setting = Some("anyone_editable".to_string());
333 self.request.allow_copy = Some(true);
334 self.request.allow_comment = Some(true);
335 self.request.allow_save_copy = Some(true);
336 self.request.watermark_setting = Some("none".to_string());
337 self.request.allow_share_partner_tenant = Some(true);
338 self
339 }
340
341 pub fn build(mut self) -> PatchPermissionPublicV2Request {
342 self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
343 self.request
344 }
345}
346
347crate::impl_executable_builder_owned!(
348 PatchPermissionPublicV2RequestBuilder,
349 crate::service::cloud_docs::permission::PermissionService,
350 PatchPermissionPublicV2Request,
351 BaseResponse<PatchPermissionPublicV2Response>,
352 patch_permission_public_v2
353);
354
355#[derive(Debug, Deserialize)]
357pub struct PermissionUpdateResultV2 {
358 pub link_share_setting: Option<String>,
360 pub allow_copy: Option<bool>,
362 pub allow_comment: Option<bool>,
364 pub allow_save_copy: Option<bool>,
366 pub watermark_setting: Option<String>,
368 pub allow_share_partner_tenant: Option<bool>,
370 pub access_setting: Option<String>,
372 pub share_scope: Option<String>,
374 pub expire_time: Option<i64>,
376 pub update_time: Option<i64>,
378}
379
380#[derive(Debug, Deserialize)]
382pub struct PatchPermissionPublicV2Response {
383 pub permission_public: PermissionUpdateResultV2,
385}
386
387impl ApiResponseTrait for PatchPermissionPublicV2Response {
388 fn data_format() -> ResponseFormat {
389 ResponseFormat::Data
390 }
391}
392
393pub async fn patch_permission_public_v2(
395 request: PatchPermissionPublicV2Request,
396 config: &Config,
397 option: Option<RequestOption>,
398) -> SDKResult<BaseResponse<PatchPermissionPublicV2Response>> {
399 let mut api_req = request.api_request;
400 api_req.http_method = Method::PATCH;
401 api_req.api_path = format!(
402 "/open-apis/drive/v2/permissions/{}/public?type={}",
403 request.token, request.obj_type
404 );
405
406 api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
407
408 let api_resp = Transport::request(api_req, config, option).await?;
409 Ok(api_resp)
410}
411
412impl PermissionUpdateResultV2 {
413 pub fn share_level_description(&self) -> Option<&'static str> {
415 self.link_share_setting
416 .as_ref()
417 .map(|setting| match setting.as_str() {
418 "closed" => "关闭分享",
419 "tenant_readable" => "组织内可读",
420 "tenant_editable" => "组织内可编辑",
421 "anyone_readable" => "任何人可读",
422 "anyone_editable" => "任何人可编辑",
423 _ => "未知设置",
424 })
425 }
426
427 pub fn has_update_time(&self) -> bool {
429 self.update_time.is_some()
430 }
431
432 pub fn has_expire_time(&self) -> bool {
434 self.expire_time.is_some()
435 }
436
437 pub fn update_time_formatted(&self) -> Option<String> {
439 self.update_time
440 .map(|timestamp| format!("更新时间: {timestamp}"))
441 }
442
443 pub fn expire_time_formatted(&self) -> Option<String> {
445 self.expire_time.map(|timestamp| {
446 if timestamp == 0 {
447 "永久有效".to_string()
448 } else {
449 let datetime =
450 chrono::DateTime::from_timestamp(timestamp, 0).unwrap_or_else(chrono::Utc::now);
451 format!("过期时间: {}", datetime.format("%Y-%m-%d %H:%M:%S"))
452 }
453 })
454 }
455
456 pub fn changes_summary(&self) -> Vec<String> {
458 let mut changes = Vec::new();
459
460 if let Some(ref setting) = self.link_share_setting {
461 changes.push(format!(
462 "分享设置: {}",
463 match setting.as_str() {
464 "closed" => "关闭分享",
465 "tenant_readable" => "组织内可读",
466 "tenant_editable" => "组织内可编辑",
467 "anyone_readable" => "任何人可读",
468 "anyone_editable" => "任何人可编辑",
469 _ => setting,
470 }
471 ));
472 }
473
474 if let Some(allow_copy) = self.allow_copy {
475 changes.push(format!(
476 "复制权限: {}",
477 if allow_copy { "允许" } else { "禁止" }
478 ));
479 }
480
481 if let Some(allow_comment) = self.allow_comment {
482 changes.push(format!(
483 "评论权限: {}",
484 if allow_comment { "允许" } else { "禁止" }
485 ));
486 }
487
488 if let Some(allow_save_copy) = self.allow_save_copy {
489 changes.push(format!(
490 "保存副本: {}",
491 if allow_save_copy { "允许" } else { "禁止" }
492 ));
493 }
494
495 if let Some(ref watermark) = self.watermark_setting {
496 changes.push(format!(
497 "水印设置: {}",
498 match watermark.as_str() {
499 "visible" => "显示水印",
500 "none" => "无水印",
501 _ => watermark,
502 }
503 ));
504 }
505
506 if let Some(allow_external) = self.allow_share_partner_tenant {
507 changes.push(format!(
508 "组织外分享: {}",
509 if allow_external { "允许" } else { "禁止" }
510 ));
511 }
512
513 if let Some(ref access) = self.access_setting {
514 changes.push(format!("访问设置: {access}"));
515 }
516
517 if let Some(ref scope) = self.share_scope {
518 changes.push(format!("分享范围: {scope}"));
519 }
520
521 if let Some(expire_time) = self.expire_time {
522 if expire_time == 0 {
523 changes.push("过期设置: 永久有效".to_string());
524 } else {
525 let datetime = chrono::DateTime::from_timestamp(expire_time, 0)
526 .unwrap_or_else(chrono::Utc::now);
527 changes.push(format!(
528 "过期设置: {}",
529 datetime.format("%Y-%m-%d %H:%M:%S")
530 ));
531 }
532 }
533
534 changes
535 }
536
537 pub fn security_level(&self) -> &'static str {
539 if let Some(ref setting) = self.link_share_setting {
540 match setting.as_str() {
541 "closed" => "最安全",
542 "tenant_readable" => {
543 if self.allow_share_partner_tenant == Some(false) {
544 "较安全"
545 } else {
546 "中等安全"
547 }
548 }
549 "tenant_editable" => "中等安全",
550 "anyone_readable" => "较低安全",
551 "anyone_editable" => "低安全",
552 _ => "未知",
553 }
554 } else {
555 "未变更"
556 }
557 }
558
559 pub fn advanced_changes(&self) -> Vec<String> {
561 let mut changes = Vec::new();
562
563 if self.access_setting.is_some() {
564 changes.push("访问权限配置已更新".to_string());
565 }
566
567 if self.share_scope.is_some() {
568 changes.push("分享范围已调整".to_string());
569 }
570
571 if self.allow_share_partner_tenant.is_some() {
572 changes.push("组织外分享权限已变更".to_string());
573 }
574
575 if self.expire_time.is_some() {
576 changes.push("过期时间已设置".to_string());
577 }
578
579 changes
580 }
581}
582
583impl PatchPermissionPublicV2Response {
584 pub fn update_result(&self) -> &PermissionUpdateResultV2 {
586 &self.permission_public
587 }
588
589 pub fn is_updated(&self) -> bool {
591 self.permission_public.link_share_setting.is_some()
593 || self.permission_public.allow_copy.is_some()
594 || self.permission_public.allow_comment.is_some()
595 || self.permission_public.allow_save_copy.is_some()
596 || self.permission_public.watermark_setting.is_some()
597 || self.permission_public.allow_share_partner_tenant.is_some()
598 || self.permission_public.access_setting.is_some()
599 || self.permission_public.share_scope.is_some()
600 || self.permission_public.expire_time.is_some()
601 }
602
603 pub fn update_summary(&self) -> String {
605 let changes = self.permission_public.changes_summary();
606 if changes.is_empty() {
607 "权限设置无变更".to_string()
608 } else {
609 format!("权限设置已更新: {}", changes.join(", "))
610 }
611 }
612
613 pub fn security_assessment(&self) -> String {
615 format!(
616 "安全级别: {} - {}",
617 self.permission_public.security_level(),
618 self.get_security_tips()
619 )
620 }
621
622 fn get_security_tips(&self) -> &'static str {
624 if let Some(ref setting) = self.permission_public.link_share_setting {
625 match setting.as_str() {
626 "closed" => "文档仅限邀请用户访问,安全性最高",
627 "tenant_readable" => {
628 if self.permission_public.allow_share_partner_tenant == Some(false) {
629 "组织内用户可查看,适合内部分享"
630 } else {
631 "允许组织外分享,注意内容安全"
632 }
633 }
634 "tenant_editable" => "组织内用户可编辑,注意权限管控",
635 "anyone_readable" => "任何人可查看,建议开启密码保护",
636 "anyone_editable" => "任何人可编辑,存在较高安全风险",
637 _ => "权限设置需要进一步确认",
638 }
639 } else {
640 "权限设置保持原有配置"
641 }
642 }
643
644 pub fn operation_recommendations(&self) -> Vec<String> {
646 let mut recommendations = Vec::new();
647
648 if let Some(ref setting) = self.permission_public.link_share_setting {
649 if setting == "anyone_editable" || setting == "anyone_readable" {
650 recommendations.push("建议设置密码保护".to_string());
651
652 if self.permission_public.allow_copy == Some(true) {
653 recommendations.push("建议禁止复制以防止内容泄露".to_string());
654 }
655
656 if self.permission_public.watermark_setting != Some("visible".to_string()) {
657 recommendations.push("建议开启水印以标识来源".to_string());
658 }
659 }
660 }
661
662 if self.permission_public.allow_share_partner_tenant == Some(true) {
663 recommendations.push("已开启组织外分享,请确保内容合规".to_string());
664 }
665
666 if let Some(expire_time) = self.permission_public.expire_time {
667 if expire_time > 0 {
668 let remaining = expire_time - chrono::Utc::now().timestamp();
669 if remaining < 86400 {
670 recommendations.push("分享即将过期,请注意及时续期".to_string());
671 }
672 }
673 }
674
675 let advanced_changes = self.permission_public.advanced_changes();
676 if !advanced_changes.is_empty() {
677 recommendations.push("已应用高级配置,请验证功能是否符合预期".to_string());
678 }
679
680 if recommendations.is_empty() {
681 recommendations.push("当前权限配置合理".to_string());
682 }
683
684 recommendations
685 }
686
687 pub fn advanced_features_report(&self) -> String {
689 let changes = self.permission_public.advanced_changes();
690 if changes.is_empty() {
691 "未更新高级功能".to_string()
692 } else {
693 format!("高级功能更新: {}", changes.join(", "))
694 }
695 }
696
697 pub fn expiration_report(&self) -> Option<String> {
699 self.permission_public.expire_time_formatted()
700 }
701}
702
703#[cfg(test)]
704mod tests {
705 use super::*;
706
707 #[test]
708 fn test_patch_permission_public_v2_request_builder() {
709 let request = PatchPermissionPublicV2Request::builder()
710 .token("doccnxxxxxx")
711 .as_doc()
712 .tenant_readable()
713 .disable_copy()
714 .enable_comment()
715 .enable_watermark()
716 .disable_external_share()
717 .build();
718
719 assert_eq!(request.token, "doccnxxxxxx");
720 assert_eq!(request.obj_type, "doc");
721 assert_eq!(
722 request.link_share_setting,
723 Some("tenant_readable".to_string())
724 );
725 assert_eq!(request.allow_copy, Some(false));
726 assert_eq!(request.allow_comment, Some(true));
727 assert_eq!(request.watermark_setting, Some("visible".to_string()));
728 assert_eq!(request.allow_share_partner_tenant, Some(false));
729 }
730
731 #[test]
732 fn test_convenience_modes() {
733 let enterprise_request = PatchPermissionPublicV2Request::builder()
734 .token("doccnxxxxxx")
735 .as_doc()
736 .enterprise_secure_mode()
737 .build();
738
739 assert_eq!(
740 enterprise_request.link_share_setting,
741 Some("tenant_readable".to_string())
742 );
743 assert_eq!(enterprise_request.allow_copy, Some(false));
744 assert_eq!(enterprise_request.allow_comment, Some(false));
745 assert_eq!(enterprise_request.allow_save_copy, Some(false));
746 assert_eq!(
747 enterprise_request.watermark_setting,
748 Some("visible".to_string())
749 );
750 assert_eq!(enterprise_request.allow_share_partner_tenant, Some(false));
751
752 let public_request = PatchPermissionPublicV2Request::builder()
753 .token("doccnxxxxxx")
754 .as_doc()
755 .public_share_mode()
756 .build();
757
758 assert_eq!(
759 public_request.link_share_setting,
760 Some("anyone_readable".to_string())
761 );
762 assert_eq!(public_request.allow_copy, Some(false));
763 assert_eq!(public_request.allow_comment, Some(true));
764 assert_eq!(public_request.allow_save_copy, Some(false));
765 assert_eq!(
766 public_request.watermark_setting,
767 Some("visible".to_string())
768 );
769 assert_eq!(public_request.allow_share_partner_tenant, Some(true));
770 }
771
772 #[test]
773 fn test_expiration_settings() {
774 let request = PatchPermissionPublicV2Request::builder()
775 .token("doccnxxxxxx")
776 .as_doc()
777 .expire_after_days(7)
778 .build();
779
780 assert!(request.expire_time.is_some());
781 assert!(request.expire_time.unwrap() > chrono::Utc::now().timestamp());
782
783 let permanent_request = PatchPermissionPublicV2Request::builder()
784 .token("doccnxxxxxx")
785 .as_doc()
786 .never_expire()
787 .build();
788
789 assert_eq!(permanent_request.expire_time, Some(0));
790 }
791
792 #[test]
793 fn test_permission_update_result_v2_methods() {
794 let result = PermissionUpdateResultV2 {
795 link_share_setting: Some("tenant_editable".to_string()),
796 allow_copy: Some(false),
797 allow_comment: Some(true),
798 allow_save_copy: Some(false),
799 watermark_setting: Some("visible".to_string()),
800 allow_share_partner_tenant: Some(false),
801 access_setting: Some("advanced".to_string()),
802 share_scope: Some("limited".to_string()),
803 expire_time: Some(chrono::Utc::now().timestamp() + 86400),
804 update_time: Some(chrono::Utc::now().timestamp()),
805 };
806
807 assert_eq!(result.share_level_description(), Some("组织内可编辑"));
808 assert!(result.has_update_time());
809 assert!(result.has_expire_time());
810 assert_eq!(result.security_level(), "中等安全");
811
812 let changes = result.changes_summary();
813 assert!(!changes.is_empty());
814 assert!(changes.iter().any(|c| c.contains("组织内可编辑")));
815 assert!(changes.iter().any(|c| c.contains("复制权限: 禁止")));
816 assert!(changes.iter().any(|c| c.contains("评论权限: 允许")));
817
818 let advanced_changes = result.advanced_changes();
819 assert!(!advanced_changes.is_empty());
820 assert!(advanced_changes
821 .iter()
822 .any(|c| c.contains("访问权限配置已更新")));
823 }
824}