open_lark/service/cloud_docs/permission/public_v2/
get.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 GetPermissionPublicV2Request {
17 #[serde(skip)]
18 api_request: ApiRequest,
19 #[serde(skip)]
21 token: String,
22 #[serde(skip)]
24 obj_type: String,
25}
26
27impl GetPermissionPublicV2Request {
28 pub fn builder() -> GetPermissionPublicV2RequestBuilder {
29 GetPermissionPublicV2RequestBuilder::default()
30 }
31
32 pub fn new(token: impl ToString, obj_type: impl ToString) -> Self {
33 Self {
34 token: token.to_string(),
35 obj_type: obj_type.to_string(),
36 ..Default::default()
37 }
38 }
39
40 pub fn for_doc(token: impl ToString) -> Self {
42 Self::new(token, "doc")
43 }
44
45 pub fn for_sheet(token: impl ToString) -> Self {
47 Self::new(token, "sheet")
48 }
49
50 pub fn for_bitable(token: impl ToString) -> Self {
52 Self::new(token, "bitable")
53 }
54
55 pub fn for_wiki(token: impl ToString) -> Self {
57 Self::new(token, "wiki")
58 }
59}
60
61#[derive(Default)]
62pub struct GetPermissionPublicV2RequestBuilder {
63 request: GetPermissionPublicV2Request,
64}
65
66impl GetPermissionPublicV2RequestBuilder {
67 pub fn token(mut self, token: impl ToString) -> Self {
69 self.request.token = token.to_string();
70 self
71 }
72
73 pub fn obj_type(mut self, obj_type: impl ToString) -> Self {
75 self.request.obj_type = obj_type.to_string();
76 self
77 }
78
79 pub fn as_doc(mut self) -> Self {
81 self.request.obj_type = "doc".to_string();
82 self
83 }
84
85 pub fn as_sheet(mut self) -> Self {
87 self.request.obj_type = "sheet".to_string();
88 self
89 }
90
91 pub fn as_bitable(mut self) -> Self {
93 self.request.obj_type = "bitable".to_string();
94 self
95 }
96
97 pub fn as_wiki(mut self) -> Self {
99 self.request.obj_type = "wiki".to_string();
100 self
101 }
102
103 pub fn build(mut self) -> GetPermissionPublicV2Request {
104 self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
105 self.request
106 }
107}
108
109crate::impl_executable_builder_owned!(
110 GetPermissionPublicV2RequestBuilder,
111 crate::service::cloud_docs::permission::PermissionService,
112 GetPermissionPublicV2Request,
113 BaseResponse<GetPermissionPublicV2Response>,
114 get_permission_public_v2
115);
116
117#[derive(Debug, Deserialize)]
119pub struct PublicSettingsV2 {
120 pub link_share_setting: String,
122 pub password_switch: bool,
124 pub allow_copy: bool,
126 pub allow_comment: bool,
128 pub allow_save_copy: bool,
130 pub access_setting: Option<String>,
132 pub watermark_setting: Option<String>,
134 pub allow_share_partner_tenant: Option<bool>,
136 pub external_access_entity: Option<serde_json::Value>,
138 pub comment_entity: Option<serde_json::Value>,
140 pub share_scope: Option<String>,
142 pub expire_time: Option<i64>,
144}
145
146#[derive(Debug, Deserialize)]
148pub struct GetPermissionPublicV2Response {
149 pub permission_public: PublicSettingsV2,
151}
152
153impl ApiResponseTrait for GetPermissionPublicV2Response {
154 fn data_format() -> ResponseFormat {
155 ResponseFormat::Data
156 }
157}
158
159pub async fn get_permission_public_v2(
161 request: GetPermissionPublicV2Request,
162 config: &Config,
163 option: Option<RequestOption>,
164) -> SDKResult<BaseResponse<GetPermissionPublicV2Response>> {
165 let mut api_req = request.api_request;
166 api_req.http_method = Method::GET;
167 api_req.api_path = format!(
168 "/open-apis/drive/v2/permissions/{}/public?type={}",
169 request.token, request.obj_type
170 );
171
172 api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
173
174 let api_resp = Transport::request(api_req, config, option).await?;
175 Ok(api_resp)
176}
177
178impl PublicSettingsV2 {
179 pub fn is_link_share_enabled(&self) -> bool {
181 self.link_share_setting == "tenant_readable"
182 || self.link_share_setting == "tenant_editable"
183 || self.link_share_setting == "anyone_readable"
184 || self.link_share_setting == "anyone_editable"
185 }
186
187 pub fn is_tenant_accessible(&self) -> bool {
189 self.link_share_setting == "tenant_readable" || self.link_share_setting == "tenant_editable"
190 }
191
192 pub fn is_anyone_accessible(&self) -> bool {
194 self.link_share_setting == "anyone_readable" || self.link_share_setting == "anyone_editable"
195 }
196
197 pub fn is_editable(&self) -> bool {
199 self.link_share_setting == "tenant_editable" || self.link_share_setting == "anyone_editable"
200 }
201
202 pub fn is_readonly(&self) -> bool {
204 self.link_share_setting == "tenant_readable" || self.link_share_setting == "anyone_readable"
205 }
206
207 pub fn has_password_protection(&self) -> bool {
209 self.password_switch
210 }
211
212 pub fn allows_external_share(&self) -> bool {
214 self.allow_share_partner_tenant.unwrap_or(false)
215 }
216
217 pub fn has_expire_time(&self) -> bool {
219 self.expire_time.is_some()
220 }
221
222 pub fn is_expired(&self) -> bool {
224 if let Some(expire_time) = self.expire_time {
225 let now = chrono::Utc::now().timestamp();
226 now > expire_time
227 } else {
228 false
229 }
230 }
231
232 pub fn share_level_description(&self) -> &'static str {
234 match self.link_share_setting.as_str() {
235 "closed" => "关闭分享",
236 "tenant_readable" => "组织内可读",
237 "tenant_editable" => "组织内可编辑",
238 "anyone_readable" => "任何人可读",
239 "anyone_editable" => "任何人可编辑",
240 _ => "未知设置",
241 }
242 }
243
244 pub fn permissions_summary(&self) -> String {
246 let mut features = Vec::new();
247
248 if self.allow_copy {
249 features.push("允许复制");
250 }
251 if self.allow_comment {
252 features.push("允许评论");
253 }
254 if self.allow_save_copy {
255 features.push("允许保存副本");
256 }
257 if self.password_switch {
258 features.push("密码保护");
259 }
260 if self.allows_external_share() {
261 features.push("组织外分享");
262 }
263
264 if features.is_empty() {
265 "基础权限".to_string()
266 } else {
267 features.join(", ")
268 }
269 }
270
271 pub fn security_level(&self) -> &'static str {
273 if self.link_share_setting == "closed" {
274 "最安全"
275 } else if self.password_switch {
276 "较安全"
277 } else if self.is_tenant_accessible() && !self.allows_external_share() {
278 "中等安全"
279 } else if self.is_anyone_accessible() || self.allows_external_share() {
280 "较低安全"
281 } else {
282 "未知"
283 }
284 }
285
286 pub fn share_scope_description(&self) -> Option<&str> {
288 self.share_scope.as_deref()
289 }
290
291 pub fn expire_time_formatted(&self) -> Option<String> {
293 self.expire_time.map(|timestamp| {
294 let datetime =
295 chrono::DateTime::from_timestamp(timestamp, 0).unwrap_or_else(chrono::Utc::now);
296 datetime.format("%Y-%m-%d %H:%M:%S").to_string()
297 })
298 }
299
300 pub fn remaining_valid_time(&self) -> Option<i64> {
302 if let Some(expire_time) = self.expire_time {
303 let now = chrono::Utc::now().timestamp();
304 if expire_time > now {
305 Some(expire_time - now)
306 } else {
307 Some(0) }
309 } else {
310 None }
312 }
313
314 pub fn advanced_features_status(&self) -> Vec<String> {
316 let mut features = Vec::new();
317
318 if let Some(access_setting) = &self.access_setting {
319 features.push(format!("访问设置: {access_setting}"));
320 }
321
322 if let Some(watermark) = &self.watermark_setting {
323 features.push(format!("水印: {watermark}"));
324 }
325
326 if self.comment_entity.is_some() {
327 features.push("自定义评论权限".to_string());
328 }
329
330 if self.external_access_entity.is_some() {
331 features.push("外部访问配置".to_string());
332 }
333
334 features
335 }
336}
337
338impl GetPermissionPublicV2Response {
339 pub fn public_settings(&self) -> &PublicSettingsV2 {
341 &self.permission_public
342 }
343
344 pub fn allows_external_access(&self) -> bool {
346 self.permission_public.is_link_share_enabled()
347 }
348
349 pub fn settings_summary(&self) -> String {
351 format!(
352 "{} - {} (安全级别: {})",
353 self.permission_public.share_level_description(),
354 self.permission_public.permissions_summary(),
355 self.permission_public.security_level()
356 )
357 }
358
359 pub fn has_advanced_config(&self) -> bool {
361 self.permission_public.external_access_entity.is_some()
362 || self.permission_public.comment_entity.is_some()
363 || self.permission_public.share_scope.is_some()
364 }
365
366 pub fn security_recommendations(&self) -> Vec<String> {
368 let mut recommendations = Vec::new();
369
370 if !self.permission_public.password_switch && self.permission_public.is_anyone_accessible()
371 {
372 recommendations.push("建议开启密码保护以提高安全性".to_string());
373 }
374
375 if self.permission_public.allow_copy && self.permission_public.is_anyone_accessible() {
376 recommendations.push("建议限制复制权限以防止内容泄露".to_string());
377 }
378
379 if self.permission_public.is_editable() && self.permission_public.is_anyone_accessible() {
380 recommendations.push("建议将编辑权限限制在组织内".to_string());
381 }
382
383 if self.permission_public.allows_external_share() {
384 recommendations.push("开启了组织外分享,请确保内容安全".to_string());
385 }
386
387 if self.permission_public.is_expired() {
388 recommendations.push("文档分享已过期,需要重新设置".to_string());
389 } else if let Some(remaining) = self.permission_public.remaining_valid_time() {
390 if remaining < 86400 {
391 recommendations.push("文档分享即将过期,请注意及时续期".to_string());
393 }
394 }
395
396 if recommendations.is_empty() {
397 recommendations.push("当前权限设置合理".to_string());
398 }
399
400 recommendations
401 }
402
403 pub fn advanced_features_report(&self) -> String {
405 let features = self.permission_public.advanced_features_status();
406 if features.is_empty() {
407 "未启用高级功能".to_string()
408 } else {
409 format!("高级功能: {}", features.join(", "))
410 }
411 }
412
413 pub fn expiration_status(&self) -> String {
415 if let Some(expire_time) = self.permission_public.expire_time_formatted() {
416 if self.permission_public.is_expired() {
417 format!("已过期: {expire_time}")
418 } else if let Some(remaining) = self.permission_public.remaining_valid_time() {
419 let days = remaining / 86400;
420 let hours = (remaining % 86400) / 3600;
421 if days > 0 {
422 format!("剩余: {days}天{hours}小时 (过期时间: {expire_time})")
423 } else {
424 format!("剩余: {hours}小时 (过期时间: {expire_time})")
425 }
426 } else {
427 format!("过期时间: {expire_time}")
428 }
429 } else {
430 "永久有效".to_string()
431 }
432 }
433}
434
435#[cfg(test)]
436mod tests {
437 use super::*;
438
439 #[test]
440 fn test_get_permission_public_v2_request_builder() {
441 let request = GetPermissionPublicV2Request::builder()
442 .token("doccnxxxxxx")
443 .as_doc()
444 .build();
445
446 assert_eq!(request.token, "doccnxxxxxx");
447 assert_eq!(request.obj_type, "doc");
448 }
449
450 #[test]
451 fn test_convenience_methods() {
452 let request = GetPermissionPublicV2Request::for_doc("doccnxxxxxx");
453 assert_eq!(request.obj_type, "doc");
454
455 let request = GetPermissionPublicV2Request::for_sheet("shtcnxxxxxx");
456 assert_eq!(request.obj_type, "sheet");
457
458 let request = GetPermissionPublicV2Request::for_bitable("bblcnxxxxxx");
459 assert_eq!(request.obj_type, "bitable");
460
461 let request = GetPermissionPublicV2Request::for_wiki("wikicnxxxxxx");
462 assert_eq!(request.obj_type, "wiki");
463 }
464
465 #[test]
466 fn test_public_settings_v2_methods() {
467 let settings = PublicSettingsV2 {
468 link_share_setting: "tenant_editable".to_string(),
469 password_switch: true,
470 allow_copy: true,
471 allow_comment: true,
472 allow_save_copy: false,
473 access_setting: Some("advanced".to_string()),
474 watermark_setting: Some("visible".to_string()),
475 allow_share_partner_tenant: Some(true),
476 external_access_entity: Some(serde_json::json!({})),
477 comment_entity: None,
478 share_scope: Some("limited".to_string()),
479 expire_time: Some(chrono::Utc::now().timestamp() + 86400), };
481
482 assert!(settings.is_link_share_enabled());
483 assert!(settings.is_tenant_accessible());
484 assert!(!settings.is_anyone_accessible());
485 assert!(settings.is_editable());
486 assert!(!settings.is_readonly());
487 assert!(settings.has_password_protection());
488 assert!(settings.allows_external_share());
489 assert!(settings.has_expire_time());
490 assert!(!settings.is_expired());
491 assert_eq!(settings.share_level_description(), "组织内可编辑");
492 assert_eq!(settings.security_level(), "较安全");
493 assert_eq!(settings.share_scope_description(), Some("limited"));
494
495 let features = settings.advanced_features_status();
496 assert!(!features.is_empty());
497 assert!(features.iter().any(|f| f.contains("访问设置")));
498 assert!(features.iter().any(|f| f.contains("水印")));
499 }
500
501 #[test]
502 fn test_expiration_logic() {
503 let expired_settings = PublicSettingsV2 {
504 link_share_setting: "anyone_readable".to_string(),
505 password_switch: false,
506 allow_copy: false,
507 allow_comment: false,
508 allow_save_copy: false,
509 access_setting: None,
510 watermark_setting: None,
511 allow_share_partner_tenant: None,
512 external_access_entity: None,
513 comment_entity: None,
514 share_scope: None,
515 expire_time: Some(chrono::Utc::now().timestamp() - 3600), };
517
518 assert!(expired_settings.is_expired());
519 assert_eq!(expired_settings.remaining_valid_time(), Some(0));
520
521 let permanent_settings = PublicSettingsV2 {
522 link_share_setting: "tenant_readable".to_string(),
523 password_switch: false,
524 allow_copy: false,
525 allow_comment: false,
526 allow_save_copy: false,
527 access_setting: None,
528 watermark_setting: None,
529 allow_share_partner_tenant: None,
530 external_access_entity: None,
531 comment_entity: None,
532 share_scope: None,
533 expire_time: None,
534 };
535
536 assert!(!permanent_settings.is_expired());
537 assert_eq!(permanent_settings.remaining_valid_time(), None);
538 }
539}