use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::core::{
api_req::ApiRequest,
api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
config::Config,
constants::AccessTokenType,
endpoints::{cloud_docs::*, EndpointBuilder},
http::Transport,
query_params::QueryParams,
req_option::RequestOption,
SDKResult,
};
#[derive(Debug, Serialize, Default, Clone)]
pub struct GetPermissionPublicRequest {
#[serde(skip)]
api_request: ApiRequest,
#[serde(skip)]
token: String,
#[serde(skip)]
obj_type: String,
}
impl GetPermissionPublicRequest {
pub fn builder() -> GetPermissionPublicRequestBuilder {
GetPermissionPublicRequestBuilder::default()
}
pub fn new(token: impl ToString, obj_type: impl ToString) -> Self {
Self {
token: token.to_string(),
obj_type: obj_type.to_string(),
..Default::default()
}
}
pub fn for_doc(token: impl ToString) -> Self {
Self::new(token, "doc")
}
pub fn for_sheet(token: impl ToString) -> Self {
Self::new(token, "sheet")
}
pub fn for_bitable(token: impl ToString) -> Self {
Self::new(token, "bitable")
}
pub fn for_wiki(token: impl ToString) -> Self {
Self::new(token, "wiki")
}
}
#[derive(Default)]
pub struct GetPermissionPublicRequestBuilder {
request: GetPermissionPublicRequest,
}
impl GetPermissionPublicRequestBuilder {
pub fn token(mut self, token: impl ToString) -> Self {
self.request.token = token.to_string();
self
}
pub fn obj_type(mut self, obj_type: impl ToString) -> Self {
self.request.obj_type = obj_type.to_string();
self
}
pub fn as_doc(mut self) -> Self {
self.request.obj_type = "doc".to_string();
self
}
pub fn as_sheet(mut self) -> Self {
self.request.obj_type = "sheet".to_string();
self
}
pub fn as_bitable(mut self) -> Self {
self.request.obj_type = "bitable".to_string();
self
}
pub fn as_wiki(mut self) -> Self {
self.request.obj_type = "wiki".to_string();
self
}
pub fn build(mut self) -> GetPermissionPublicRequest {
self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
self.request
}
}
#[derive(Debug, Deserialize)]
pub struct PublicSettings {
pub link_share_setting: String,
pub password_switch: bool,
pub allow_copy: bool,
pub allow_comment: bool,
pub allow_save_copy: bool,
pub access_setting: Option<String>,
pub watermark_setting: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct GetPermissionPublicResponse {
pub permission_public: PublicSettings,
pub external_access: Option<serde_json::Value>,
}
impl ApiResponseTrait for GetPermissionPublicResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
pub async fn get_permission_public(
request: GetPermissionPublicRequest,
config: &Config,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<GetPermissionPublicResponse>> {
let mut api_req = request.api_request;
api_req.http_method = Method::GET;
api_req.api_path =
EndpointBuilder::replace_param(DRIVE_V1_PERMISSIONS_PUBLIC, "token", &request.token);
api_req
.query_params
.insert(QueryParams::TYPE, request.obj_type);
api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
let api_resp = Transport::request(api_req, config, option).await?;
Ok(api_resp)
}
impl PublicSettings {
pub fn is_link_share_enabled(&self) -> bool {
self.link_share_setting == "tenant_readable"
|| self.link_share_setting == "tenant_editable"
|| self.link_share_setting == "anyone_readable"
|| self.link_share_setting == "anyone_editable"
}
pub fn is_tenant_accessible(&self) -> bool {
self.link_share_setting == "tenant_readable" || self.link_share_setting == "tenant_editable"
}
pub fn is_anyone_accessible(&self) -> bool {
self.link_share_setting == "anyone_readable" || self.link_share_setting == "anyone_editable"
}
pub fn is_editable(&self) -> bool {
self.link_share_setting == "tenant_editable" || self.link_share_setting == "anyone_editable"
}
pub fn is_readonly(&self) -> bool {
self.link_share_setting == "tenant_readable" || self.link_share_setting == "anyone_readable"
}
pub fn has_password_protection(&self) -> bool {
self.password_switch
}
pub fn share_level_description(&self) -> &'static str {
match self.link_share_setting.as_str() {
"closed" => "关闭分享",
"tenant_readable" => "组织内可读",
"tenant_editable" => "组织内可编辑",
"anyone_readable" => "任何人可读",
"anyone_editable" => "任何人可编辑",
_ => "未知设置",
}
}
pub fn permissions_summary(&self) -> String {
let mut features = Vec::new();
if self.allow_copy {
features.push("允许复制");
}
if self.allow_comment {
features.push("允许评论");
}
if self.allow_save_copy {
features.push("允许保存副本");
}
if self.password_switch {
features.push("密码保护");
}
if features.is_empty() {
"基础权限".to_string()
} else {
features.join(", ")
}
}
pub fn security_level(&self) -> &'static str {
if self.link_share_setting == "closed" {
"最安全"
} else if self.password_switch {
"较安全"
} else if self.is_tenant_accessible() {
"中等安全"
} else if self.is_anyone_accessible() {
"较低安全"
} else {
"未知"
}
}
}
impl GetPermissionPublicResponse {
pub fn public_settings(&self) -> &PublicSettings {
&self.permission_public
}
pub fn allows_external_access(&self) -> bool {
self.permission_public.is_link_share_enabled()
}
pub fn settings_summary(&self) -> String {
format!(
"{} - {} (安全级别: {})",
self.permission_public.share_level_description(),
self.permission_public.permissions_summary(),
self.permission_public.security_level()
)
}
pub fn has_external_config(&self) -> bool {
self.external_access.is_some()
}
pub fn security_recommendations(&self) -> Vec<String> {
let mut recommendations = Vec::new();
if !self.permission_public.password_switch && self.permission_public.is_anyone_accessible()
{
recommendations.push("建议开启密码保护以提高安全性".to_string());
}
if self.permission_public.allow_copy && self.permission_public.is_anyone_accessible() {
recommendations.push("建议限制复制权限以防止内容泄露".to_string());
}
if self.permission_public.is_editable() && self.permission_public.is_anyone_accessible() {
recommendations.push("建议将编辑权限限制在组织内".to_string());
}
if recommendations.is_empty() {
recommendations.push("当前权限设置合理".to_string());
}
recommendations
}
}
#[cfg(test)]
#[allow(unused_variables, unused_unsafe)]
mod tests {
use super::*;
#[test]
fn test_get_permission_public_request_builder() {
let request = GetPermissionPublicRequest::builder()
.token("doccnxxxxxx")
.as_doc()
.build();
assert_eq!(request.token, "doccnxxxxxx");
assert_eq!(request.obj_type, "doc");
}
#[test]
fn test_convenience_methods() {
let request = GetPermissionPublicRequest::for_doc("doccnxxxxxx");
assert_eq!(request.obj_type, "doc");
let request = GetPermissionPublicRequest::for_sheet("shtcnxxxxxx");
assert_eq!(request.obj_type, "sheet");
let request = GetPermissionPublicRequest::for_bitable("bblcnxxxxxx");
assert_eq!(request.obj_type, "bitable");
let request = GetPermissionPublicRequest::for_wiki("wikicnxxxxxx");
assert_eq!(request.obj_type, "wiki");
}
#[test]
fn test_public_settings_methods() {
let settings = PublicSettings {
link_share_setting: "tenant_editable".to_string(),
password_switch: true,
allow_copy: true,
allow_comment: true,
allow_save_copy: false,
access_setting: None,
watermark_setting: None,
};
assert!(settings.is_link_share_enabled());
assert!(settings.is_tenant_accessible());
assert!(!settings.is_anyone_accessible());
assert!(settings.is_editable());
assert!(!settings.is_readonly());
assert!(settings.has_password_protection());
assert_eq!(settings.share_level_description(), "组织内可编辑");
assert_eq!(settings.security_level(), "较安全");
}
}