use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::{
core::{
api_req::ApiRequest,
api_resp::{ApiResponseTrait, BaseResponse},
config::Config,
constants::AccessTokenType,
endpoints::cloud_docs::*,
http::Transport,
req_option::RequestOption,
SDKResult,
},
impl_executable_builder_owned,
};
pub struct PermissionsService {
config: Config,
}
impl PermissionsService {
pub fn new(config: Config) -> Self {
Self { config }
}
pub async fn get(
&self,
request: GetPermissionRequest,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<GetPermissionResponse>> {
let mut api_req = request.api_request;
api_req.http_method = Method::GET;
api_req.api_path = DRIVE_V2_PERMISSIONS_PUBLIC.replace("{}", &request.token);
api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
let api_resp = Transport::request(api_req, &self.config, option).await?;
Ok(api_resp)
}
pub async fn patch(
&self,
request: PatchPermissionRequest,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<GetPermissionResponse>> {
let mut api_req = request.api_request;
api_req.http_method = Method::PATCH;
api_req.api_path = DRIVE_V2_PERMISSIONS_PUBLIC.replace("{}", &request.token);
api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
let api_resp = Transport::request(api_req, &self.config, option).await?;
Ok(api_resp)
}
}
#[derive(Debug, Default)]
pub struct GetPermissionRequest {
api_request: ApiRequest,
token: String,
r#type: String,
}
impl GetPermissionRequest {
pub fn builder() -> GetPermissionRequestBuilder {
GetPermissionRequestBuilder::default()
}
}
#[derive(Default)]
pub struct GetPermissionRequestBuilder {
request: GetPermissionRequest,
}
impl GetPermissionRequestBuilder {
pub fn token(mut self, token: impl ToString) -> Self {
self.request.token = token.to_string();
self
}
pub fn r#type(mut self, r#type: impl ToString) -> Self {
self.request.r#type = r#type.to_string();
self.request
.api_request
.query_params
.insert("type", r#type.to_string());
self
}
pub fn build(self) -> GetPermissionRequest {
self.request
}
}
#[derive(Debug, Deserialize)]
pub struct GetPermissionResponse {
pub permission_public: PermissionPublic,
}
impl ApiResponseTrait for GetPermissionResponse {
fn data_format() -> crate::core::api_resp::ResponseFormat {
crate::core::api_resp::ResponseFormat::Data
}
}
#[derive(Debug, Deserialize)]
pub struct PermissionPublic {
pub external_access_entity: Option<String>,
pub security_entity: Option<String>,
pub comment_entity: Option<String>,
pub share_entity: Option<String>,
pub manage_collaborator_entity: Option<String>,
pub link_share_entity: Option<String>,
pub copy_entity: Option<String>,
pub lock_switch: Option<bool>,
}
#[derive(Debug, Default, Serialize)]
pub struct PatchPermissionRequest {
#[serde(skip)]
api_request: ApiRequest,
#[serde(skip)]
token: String,
#[serde(skip_serializing_if = "Option::is_none")]
external_access_entity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
security_entity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
comment_entity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
share_entity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
manage_collaborator_entity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
link_share_entity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
copy_entity: Option<String>,
}
impl PatchPermissionRequest {
pub fn builder() -> PatchPermissionRequestBuilder {
PatchPermissionRequestBuilder::default()
}
}
#[derive(Default)]
pub struct PatchPermissionRequestBuilder {
request: PatchPermissionRequest,
}
impl PatchPermissionRequestBuilder {
pub fn token(mut self, token: impl ToString) -> Self {
self.request.token = token.to_string();
self
}
pub fn r#type(mut self, r#type: impl ToString) -> Self {
self.request
.api_request
.query_params
.insert("type", r#type.to_string());
self
}
pub fn external_access_entity(mut self, external_access_entity: impl ToString) -> Self {
self.request.external_access_entity = Some(external_access_entity.to_string());
self
}
pub fn security_entity(mut self, security_entity: impl ToString) -> Self {
self.request.security_entity = Some(security_entity.to_string());
self
}
pub fn comment_entity(mut self, comment_entity: impl ToString) -> Self {
self.request.comment_entity = Some(comment_entity.to_string());
self
}
pub fn share_entity(mut self, share_entity: impl ToString) -> Self {
self.request.share_entity = Some(share_entity.to_string());
self
}
pub fn manage_collaborator_entity(mut self, manage_collaborator_entity: impl ToString) -> Self {
self.request.manage_collaborator_entity = Some(manage_collaborator_entity.to_string());
self
}
pub fn link_share_entity(mut self, link_share_entity: impl ToString) -> Self {
self.request.link_share_entity = Some(link_share_entity.to_string());
self
}
pub fn copy_entity(mut self, copy_entity: impl ToString) -> Self {
self.request.copy_entity = Some(copy_entity.to_string());
self
}
pub fn build(mut self) -> PatchPermissionRequest {
self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
self.request
}
}
impl_executable_builder_owned!(
GetPermissionRequestBuilder,
PermissionsService,
GetPermissionRequest,
BaseResponse<GetPermissionResponse>,
get
);
impl_executable_builder_owned!(
PatchPermissionRequestBuilder,
PermissionsService,
PatchPermissionRequest,
BaseResponse<GetPermissionResponse>,
patch
);
#[cfg(test)]
mod tests {
use super::*;
use crate::core::api_resp::ResponseFormat;
use rstest::rstest;
fn create_test_config() -> Config {
Config::builder()
.app_id("test_app_id")
.app_secret("test_app_secret")
.build()
}
fn create_test_permission_public() -> PermissionPublic {
PermissionPublic {
external_access_entity: Some("open".to_string()),
security_entity: Some("anyone_can_view".to_string()),
comment_entity: Some("anyone_can_view".to_string()),
share_entity: Some("anyone".to_string()),
manage_collaborator_entity: Some("collaborator_can_view".to_string()),
link_share_entity: Some("tenant_readable".to_string()),
copy_entity: Some("anyone_can_view".to_string()),
lock_switch: Some(false),
}
}
#[test]
fn test_permissions_service_new() {
let config = create_test_config();
let service = PermissionsService::new(config);
assert!(std::ptr::addr_of!(service).is_aligned());
}
#[test]
fn test_get_permission_request_builder_basic() {
let request = GetPermissionRequest::builder()
.token("test_token_123")
.r#type("doc")
.build();
assert_eq!(request.token, "test_token_123");
assert_eq!(request.r#type, "doc");
assert!(request.api_request.query_params.contains_key("type"));
assert_eq!(request.api_request.query_params.get("type").unwrap(), "doc");
}
#[rstest]
#[case("doc", "旧版文档")]
#[case("sheet", "电子表格")]
#[case("file", "云空间文件")]
#[case("wiki", "知识库节点")]
#[case("bitable", "多维表格")]
#[case("docx", "新版文档")]
#[case("mindnote", "思维笔记")]
#[case("minutes", "妙记")]
#[case("slides", "幻灯片")]
fn test_get_permission_request_all_file_types(
#[case] file_type: &str,
#[case] _description: &str,
) {
let request = GetPermissionRequest::builder()
.token("test_token")
.r#type(file_type)
.build();
assert_eq!(request.r#type, file_type);
assert_eq!(
request.api_request.query_params.get("type").unwrap(),
file_type
);
}
#[test]
fn test_get_permission_request_builder_method_chaining() {
let request = GetPermissionRequest::builder()
.token("chain_token")
.r#type("sheet")
.build();
assert_eq!(request.token, "chain_token");
assert_eq!(request.r#type, "sheet");
}
#[test]
fn test_get_permission_request_default() {
let request = GetPermissionRequest::default();
assert_eq!(request.token, "");
assert_eq!(request.r#type, "");
assert!(request.api_request.query_params.is_empty());
}
#[test]
fn test_get_permission_request_builder_overwrite() {
let request = GetPermissionRequest::builder()
.token("first_token")
.r#type("doc")
.token("second_token") .r#type("sheet") .build();
assert_eq!(request.token, "second_token");
assert_eq!(request.r#type, "sheet");
assert_eq!(
request.api_request.query_params.get("type").unwrap(),
"sheet"
);
}
#[test]
fn test_patch_permission_request_builder_basic() {
let request = PatchPermissionRequest::builder()
.token("patch_token")
.r#type("docx")
.external_access_entity("open")
.build();
assert_eq!(request.token, "patch_token");
assert_eq!(request.external_access_entity, Some("open".to_string()));
assert!(request.api_request.query_params.contains_key("type"));
assert_eq!(
request.api_request.query_params.get("type").unwrap(),
"docx"
);
}
#[test]
fn test_patch_permission_request_all_entities() {
let request = PatchPermissionRequest::builder()
.token("full_patch_token")
.r#type("doc")
.external_access_entity("open")
.security_entity("anyone_can_view")
.comment_entity("anyone_can_edit")
.share_entity("same_tenant")
.manage_collaborator_entity("collaborator_can_edit")
.link_share_entity("tenant_editable")
.copy_entity("only_full_access")
.build();
assert_eq!(request.token, "full_patch_token");
assert_eq!(request.external_access_entity, Some("open".to_string()));
assert_eq!(request.security_entity, Some("anyone_can_view".to_string()));
assert_eq!(request.comment_entity, Some("anyone_can_edit".to_string()));
assert_eq!(request.share_entity, Some("same_tenant".to_string()));
assert_eq!(
request.manage_collaborator_entity,
Some("collaborator_can_edit".to_string())
);
assert_eq!(
request.link_share_entity,
Some("tenant_editable".to_string())
);
assert_eq!(request.copy_entity, Some("only_full_access".to_string()));
}
#[rstest]
#[case("open", "打开")]
#[case("closed", "关闭")]
#[case("allow_share_partner_tenant", "允许分享给关联组织")]
fn test_patch_external_access_entity_values(#[case] value: &str, #[case] _description: &str) {
let request = PatchPermissionRequest::builder()
.token("test")
.external_access_entity(value)
.build();
assert_eq!(request.external_access_entity, Some(value.to_string()));
}
#[rstest]
#[case("anyone_can_view", "拥有可阅读权限的用户")]
#[case("anyone_can_edit", "拥有可编辑权限的用户")]
#[case("only_full_access", "拥有可管理权限的用户")]
fn test_patch_security_entity_values(#[case] value: &str, #[case] _description: &str) {
let request = PatchPermissionRequest::builder()
.token("test")
.security_entity(value)
.build();
assert_eq!(request.security_entity, Some(value.to_string()));
}
#[rstest]
#[case("anyone_can_view", "拥有可阅读权限的用户")]
#[case("anyone_can_edit", "拥有可编辑权限的用户")]
fn test_patch_comment_entity_values(#[case] value: &str, #[case] _description: &str) {
let request = PatchPermissionRequest::builder()
.token("test")
.comment_entity(value)
.build();
assert_eq!(request.comment_entity, Some(value.to_string()));
}
#[rstest]
#[case("anyone", "所有可阅读或编辑此文档的用户")]
#[case("same_tenant", "组织内所有可阅读或编辑此文档的用户")]
fn test_patch_share_entity_values(#[case] value: &str, #[case] _description: &str) {
let request = PatchPermissionRequest::builder()
.token("test")
.share_entity(value)
.build();
assert_eq!(request.share_entity, Some(value.to_string()));
}
#[rstest]
#[case("collaborator_can_view", "拥有可阅读权限的协作者")]
#[case("collaborator_can_edit", "拥有可编辑权限的协作者")]
#[case("collaborator_full_access", "拥有可管理权限的协作者")]
fn test_patch_manage_collaborator_entity_values(
#[case] value: &str,
#[case] _description: &str,
) {
let request = PatchPermissionRequest::builder()
.token("test")
.manage_collaborator_entity(value)
.build();
assert_eq!(request.manage_collaborator_entity, Some(value.to_string()));
}
#[rstest]
#[case("tenant_readable", "组织内获得链接的人可阅读")]
#[case("tenant_editable", "组织内获得链接的人可编辑")]
#[case("partner_tenant_readable", "关联组织的人可阅读")]
#[case("partner_tenant_editable", "关联组织的人可编辑")]
#[case("anyone_readable", "互联网上获得链接的任何人可阅读")]
#[case("anyone_editable", "互联网上获得链接的任何人可编辑")]
#[case("closed", "关闭链接分享")]
fn test_patch_link_share_entity_values(#[case] value: &str, #[case] _description: &str) {
let request = PatchPermissionRequest::builder()
.token("test")
.link_share_entity(value)
.build();
assert_eq!(request.link_share_entity, Some(value.to_string()));
}
#[test]
fn test_patch_permission_request_default() {
let request = PatchPermissionRequest::default();
assert_eq!(request.token, "");
assert_eq!(request.external_access_entity, None);
assert_eq!(request.security_entity, None);
assert_eq!(request.comment_entity, None);
assert_eq!(request.share_entity, None);
assert_eq!(request.manage_collaborator_entity, None);
assert_eq!(request.link_share_entity, None);
assert_eq!(request.copy_entity, None);
}
#[test]
fn test_patch_permission_request_partial_update() {
let request = PatchPermissionRequest::builder()
.token("partial_token")
.external_access_entity("closed")
.security_entity("only_full_access")
.build();
assert_eq!(request.token, "partial_token");
assert_eq!(request.external_access_entity, Some("closed".to_string()));
assert_eq!(
request.security_entity,
Some("only_full_access".to_string())
);
assert_eq!(request.comment_entity, None);
assert_eq!(request.share_entity, None);
assert_eq!(request.manage_collaborator_entity, None);
assert_eq!(request.link_share_entity, None);
assert_eq!(request.copy_entity, None);
}
#[test]
fn test_get_permission_response_api_trait() {
let format = GetPermissionResponse::data_format();
assert_eq!(format, ResponseFormat::Data);
}
#[test]
fn test_permission_public_creation() {
let permission = create_test_permission_public();
assert_eq!(permission.external_access_entity, Some("open".to_string()));
assert_eq!(
permission.security_entity,
Some("anyone_can_view".to_string())
);
assert_eq!(
permission.comment_entity,
Some("anyone_can_view".to_string())
);
assert_eq!(permission.share_entity, Some("anyone".to_string()));
assert_eq!(
permission.manage_collaborator_entity,
Some("collaborator_can_view".to_string())
);
assert_eq!(
permission.link_share_entity,
Some("tenant_readable".to_string())
);
assert_eq!(permission.copy_entity, Some("anyone_can_view".to_string()));
assert_eq!(permission.lock_switch, Some(false));
}
#[test]
fn test_permission_public_optional_fields() {
let permission = PermissionPublic {
external_access_entity: None,
security_entity: None,
comment_entity: None,
share_entity: None,
manage_collaborator_entity: None,
link_share_entity: None,
copy_entity: None,
lock_switch: None,
};
assert_eq!(permission.external_access_entity, None);
assert_eq!(permission.security_entity, None);
assert_eq!(permission.comment_entity, None);
assert_eq!(permission.share_entity, None);
assert_eq!(permission.manage_collaborator_entity, None);
assert_eq!(permission.link_share_entity, None);
assert_eq!(permission.copy_entity, None);
assert_eq!(permission.lock_switch, None);
}
#[test]
fn test_get_permission_response_creation() {
let permission_public = create_test_permission_public();
let response = GetPermissionResponse { permission_public };
assert_eq!(
response.permission_public.external_access_entity,
Some("open".to_string())
);
assert_eq!(response.permission_public.lock_switch, Some(false));
}
#[test]
fn test_patch_permission_request_serialization() {
let request = PatchPermissionRequest::builder()
.token("ser_token")
.external_access_entity("open")
.security_entity("anyone_can_view")
.build();
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("\"external_access_entity\":\"open\""));
assert!(json.contains("\"security_entity\":\"anyone_can_view\""));
assert!(!json.contains("ser_token"));
}
#[test]
fn test_patch_permission_request_serialization_skip_none() {
let request = PatchPermissionRequest::builder()
.token("skip_token")
.external_access_entity("closed")
.build();
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("\"external_access_entity\":\"closed\""));
assert!(!json.contains("security_entity"));
assert!(!json.contains("comment_entity"));
assert!(!json.contains("share_entity"));
}
#[test]
fn test_get_permission_response_deserialization() {
let json = r#"{
"permission_public": {
"external_access_entity": "open",
"security_entity": "anyone_can_view",
"comment_entity": "anyone_can_edit",
"share_entity": "same_tenant",
"manage_collaborator_entity": "collaborator_can_view",
"link_share_entity": "tenant_readable",
"copy_entity": "only_full_access",
"lock_switch": true
}
}"#;
let response: GetPermissionResponse = serde_json::from_str(json).unwrap();
assert_eq!(
response.permission_public.external_access_entity,
Some("open".to_string())
);
assert_eq!(
response.permission_public.security_entity,
Some("anyone_can_view".to_string())
);
assert_eq!(
response.permission_public.comment_entity,
Some("anyone_can_edit".to_string())
);
assert_eq!(
response.permission_public.share_entity,
Some("same_tenant".to_string())
);
assert_eq!(
response.permission_public.manage_collaborator_entity,
Some("collaborator_can_view".to_string())
);
assert_eq!(
response.permission_public.link_share_entity,
Some("tenant_readable".to_string())
);
assert_eq!(
response.permission_public.copy_entity,
Some("only_full_access".to_string())
);
assert_eq!(response.permission_public.lock_switch, Some(true));
}
#[test]
fn test_permission_public_deserialization_partial() {
let json = r#"{
"external_access_entity": "closed",
"lock_switch": false
}"#;
let permission: PermissionPublic = serde_json::from_str(json).unwrap();
assert_eq!(
permission.external_access_entity,
Some("closed".to_string())
);
assert_eq!(permission.lock_switch, Some(false));
assert_eq!(permission.security_entity, None);
assert_eq!(permission.comment_entity, None);
assert_eq!(permission.share_entity, None);
}
#[test]
fn test_get_permission_request_unicode_token() {
let unicode_token = "测试令牌_🔑_token";
let request = GetPermissionRequest::builder()
.token(unicode_token)
.r#type("doc")
.build();
assert_eq!(request.token, unicode_token);
}
#[test]
fn test_patch_permission_request_unicode_values() {
let request = PatchPermissionRequest::builder()
.token("unicode_test")
.external_access_entity("测试值")
.security_entity("权限值")
.build();
assert_eq!(request.external_access_entity, Some("测试值".to_string()));
assert_eq!(request.security_entity, Some("权限值".to_string()));
}
#[test]
fn test_get_permission_request_empty_values() {
let request = GetPermissionRequest::builder().token("").r#type("").build();
assert_eq!(request.token, "");
assert_eq!(request.r#type, "");
assert_eq!(request.api_request.query_params.get("type").unwrap(), "");
}
#[test]
fn test_patch_permission_request_empty_values() {
let request = PatchPermissionRequest::builder()
.token("")
.external_access_entity("")
.security_entity("")
.build();
assert_eq!(request.token, "");
assert_eq!(request.external_access_entity, Some("".to_string()));
assert_eq!(request.security_entity, Some("".to_string()));
}
#[test]
fn test_long_token_handling() {
let long_token = "a".repeat(1000);
let request = GetPermissionRequest::builder()
.token(&long_token)
.r#type("doc")
.build();
assert_eq!(request.token, long_token);
}
#[test]
fn test_special_characters_in_token() {
let special_token = "token-with_special.chars@123#";
let request = PatchPermissionRequest::builder()
.token(special_token)
.external_access_entity("open")
.build();
assert_eq!(request.token, special_token);
}
#[test]
fn test_debug_implementations() {
let get_request = GetPermissionRequest::builder()
.token("debug_test")
.r#type("doc")
.build();
let patch_request = PatchPermissionRequest::builder()
.token("debug_patch")
.external_access_entity("open")
.build();
let permission = create_test_permission_public();
let response = GetPermissionResponse {
permission_public: permission,
};
let _debug_get = format!("{:?}", get_request);
let _debug_patch = format!("{:?}", patch_request);
let _debug_response = format!("{:?}", response);
let _debug_permission = format!("{:?}", response.permission_public);
}
#[test]
fn test_get_permission_builder_reuse() {
let builder = GetPermissionRequest::builder()
.token("reuse_test")
.r#type("sheet");
let request1 = builder.build();
assert_eq!(request1.token, "reuse_test");
assert_eq!(request1.r#type, "sheet");
}
#[test]
fn test_patch_permission_builder_complex_chaining() {
let request = PatchPermissionRequest::builder()
.token("complex_chain")
.r#type("bitable")
.external_access_entity("open")
.security_entity("anyone_can_view")
.comment_entity("anyone_can_edit")
.share_entity("anyone")
.manage_collaborator_entity("collaborator_can_edit")
.link_share_entity("anyone_editable")
.copy_entity("anyone_can_view")
.build();
assert_eq!(request.token, "complex_chain");
assert_eq!(request.external_access_entity, Some("open".to_string()));
assert_eq!(request.security_entity, Some("anyone_can_view".to_string()));
assert_eq!(request.comment_entity, Some("anyone_can_edit".to_string()));
assert_eq!(request.share_entity, Some("anyone".to_string()));
assert_eq!(
request.manage_collaborator_entity,
Some("collaborator_can_edit".to_string())
);
assert_eq!(
request.link_share_entity,
Some("anyone_editable".to_string())
);
assert_eq!(request.copy_entity, Some("anyone_can_view".to_string()));
assert_eq!(
request.api_request.query_params.get("type").unwrap(),
"bitable"
);
}
#[test]
fn test_patch_permission_request_body_generation() {
let request = PatchPermissionRequest::builder()
.token("body_test")
.external_access_entity("closed")
.security_entity("only_full_access")
.build();
assert!(!request.api_request.body.is_empty());
let body_str = String::from_utf8(request.api_request.body).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&body_str).unwrap();
assert_eq!(parsed["external_access_entity"], "closed");
assert_eq!(parsed["security_entity"], "only_full_access");
assert!(parsed.get("token").is_none());
}
}