open_lark/service/cloud_docs/permission/public_v2/
get.rs

1use 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/// 获取云文档权限设置请求 (v2)
15#[derive(Debug, Serialize, Default, Clone)]
16pub struct GetPermissionPublicV2Request {
17    #[serde(skip)]
18    api_request: ApiRequest,
19    /// 文档token
20    #[serde(skip)]
21    token: String,
22    /// 文档类型
23    #[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    /// 获取文档权限设置
41    pub fn for_doc(token: impl ToString) -> Self {
42        Self::new(token, "doc")
43    }
44
45    /// 获取电子表格权限设置
46    pub fn for_sheet(token: impl ToString) -> Self {
47        Self::new(token, "sheet")
48    }
49
50    /// 获取多维表格权限设置
51    pub fn for_bitable(token: impl ToString) -> Self {
52        Self::new(token, "bitable")
53    }
54
55    /// 获取知识库权限设置
56    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    /// 文档token
68    pub fn token(mut self, token: impl ToString) -> Self {
69        self.request.token = token.to_string();
70        self
71    }
72
73    /// 文档类型
74    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    /// 设置为文档类型
80    pub fn as_doc(mut self) -> Self {
81        self.request.obj_type = "doc".to_string();
82        self
83    }
84
85    /// 设置为电子表格类型
86    pub fn as_sheet(mut self) -> Self {
87        self.request.obj_type = "sheet".to_string();
88        self
89    }
90
91    /// 设置为多维表格类型
92    pub fn as_bitable(mut self) -> Self {
93        self.request.obj_type = "bitable".to_string();
94        self
95    }
96
97    /// 设置为知识库类型
98    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/// 公开访问设置 (v2)
118#[derive(Debug, Deserialize)]
119pub struct PublicSettingsV2 {
120    /// 链接分享设置
121    pub link_share_setting: String,
122    /// 密码保护开关
123    pub password_switch: bool,
124    /// 是否允许复制
125    pub allow_copy: bool,
126    /// 是否允许评论
127    pub allow_comment: bool,
128    /// 是否允许保存副本
129    pub allow_save_copy: bool,
130    /// 访问权限
131    pub access_setting: Option<String>,
132    /// 水印设置
133    pub watermark_setting: Option<String>,
134    /// 是否允许分享到组织外
135    pub allow_share_partner_tenant: Option<bool>,
136    /// 外部分享设置
137    pub external_access_entity: Option<serde_json::Value>,
138    /// 评论权限设置
139    pub comment_entity: Option<serde_json::Value>,
140    /// 分享范围设置
141    pub share_scope: Option<String>,
142    /// 到期时间
143    pub expire_time: Option<i64>,
144}
145
146/// 获取云文档权限设置响应 (v2)
147#[derive(Debug, Deserialize)]
148pub struct GetPermissionPublicV2Response {
149    /// 公开访问设置
150    pub permission_public: PublicSettingsV2,
151}
152
153impl ApiResponseTrait for GetPermissionPublicV2Response {
154    fn data_format() -> ResponseFormat {
155        ResponseFormat::Data
156    }
157}
158
159/// 获取云文档权限设置 (v2)
160pub 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    /// 是否开启了链接分享
180    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    /// 是否允许组织内访问
188    pub fn is_tenant_accessible(&self) -> bool {
189        self.link_share_setting == "tenant_readable" || self.link_share_setting == "tenant_editable"
190    }
191
192    /// 是否允许任何人访问
193    pub fn is_anyone_accessible(&self) -> bool {
194        self.link_share_setting == "anyone_readable" || self.link_share_setting == "anyone_editable"
195    }
196
197    /// 是否允许编辑
198    pub fn is_editable(&self) -> bool {
199        self.link_share_setting == "tenant_editable" || self.link_share_setting == "anyone_editable"
200    }
201
202    /// 是否仅可读
203    pub fn is_readonly(&self) -> bool {
204        self.link_share_setting == "tenant_readable" || self.link_share_setting == "anyone_readable"
205    }
206
207    /// 是否开启密码保护
208    pub fn has_password_protection(&self) -> bool {
209        self.password_switch
210    }
211
212    /// 是否允许分享到组织外
213    pub fn allows_external_share(&self) -> bool {
214        self.allow_share_partner_tenant.unwrap_or(false)
215    }
216
217    /// 是否有过期时间
218    pub fn has_expire_time(&self) -> bool {
219        self.expire_time.is_some()
220    }
221
222    /// 是否已过期
223    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    /// 获取分享级别描述
233    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    /// 获取权限摘要
245    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    /// 获取安全级别
272    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    /// 获取分享范围描述
287    pub fn share_scope_description(&self) -> Option<&str> {
288        self.share_scope.as_deref()
289    }
290
291    /// 获取过期时间格式化字符串
292    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    /// 获取剩余有效时间(秒)
301    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) // 已过期
308            }
309        } else {
310            None // 永久有效
311        }
312    }
313
314    /// 获取高级功能状态
315    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    /// 获取公开设置
340    pub fn public_settings(&self) -> &PublicSettingsV2 {
341        &self.permission_public
342    }
343
344    /// 是否允许外部访问
345    pub fn allows_external_access(&self) -> bool {
346        self.permission_public.is_link_share_enabled()
347    }
348
349    /// 获取设置摘要
350    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    /// 是否有高级配置
360    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    /// 安全性建议
367    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                // 少于24小时
392                recommendations.push("文档分享即将过期,请注意及时续期".to_string());
393            }
394        }
395
396        if recommendations.is_empty() {
397            recommendations.push("当前权限设置合理".to_string());
398        }
399
400        recommendations
401    }
402
403    /// 获取高级功能报告
404    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    /// 过期状态检查
414    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), // 24小时后过期
480        };
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), // 1小时前过期
516        };
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}