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