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