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,
req_option::RequestOption,
SDKResult,
};
#[derive(Debug, Serialize, Default, Clone)]
pub struct TransferOwnerRequest {
#[serde(skip)]
api_request: ApiRequest,
#[serde(skip)]
token: String,
#[serde(skip)]
obj_type: String,
member_type: String,
member_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
remove_old_owner: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
need_notification: Option<bool>,
}
impl TransferOwnerRequest {
pub fn builder() -> TransferOwnerRequestBuilder {
TransferOwnerRequestBuilder::default()
}
pub fn new(
token: impl ToString,
obj_type: impl ToString,
member_type: impl ToString,
member_id: impl ToString,
) -> Self {
Self {
token: token.to_string(),
obj_type: obj_type.to_string(),
member_type: member_type.to_string(),
member_id: member_id.to_string(),
..Default::default()
}
}
pub fn to_user(token: impl ToString, obj_type: impl ToString, user_id: impl ToString) -> Self {
Self::new(token, obj_type, "user", user_id)
}
}
#[derive(Default)]
pub struct TransferOwnerRequestBuilder {
request: TransferOwnerRequest,
}
impl TransferOwnerRequestBuilder {
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 new_owner(mut self, member_type: impl ToString, member_id: impl ToString) -> Self {
self.request.member_type = member_type.to_string();
self.request.member_id = member_id.to_string();
self
}
pub fn to_user(mut self, user_id: impl ToString) -> Self {
self.request.member_type = "user".to_string();
self.request.member_id = user_id.to_string();
self
}
pub fn to_chat(mut self, chat_id: impl ToString) -> Self {
self.request.member_type = "chat".to_string();
self.request.member_id = chat_id.to_string();
self
}
pub fn to_department(mut self, department_id: impl ToString) -> Self {
self.request.member_type = "department".to_string();
self.request.member_id = department_id.to_string();
self
}
pub fn remove_old_owner(mut self, remove: bool) -> Self {
self.request.remove_old_owner = Some(remove);
self
}
pub fn remove_current_owner(mut self) -> Self {
self.request.remove_old_owner = Some(true);
self
}
pub fn keep_current_owner(mut self) -> Self {
self.request.remove_old_owner = Some(false);
self
}
pub fn need_notification(mut self, need: bool) -> Self {
self.request.need_notification = Some(need);
self
}
pub fn with_notification(mut self) -> Self {
self.request.need_notification = Some(true);
self
}
pub fn without_notification(mut self) -> Self {
self.request.need_notification = Some(false);
self
}
pub fn build(mut self) -> TransferOwnerRequest {
self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
self.request
}
}
#[derive(Debug, Deserialize)]
pub struct TransferResult {
pub member_type: String,
pub member_id: String,
pub transfer_time: Option<i64>,
pub old_owner_type: Option<String>,
pub old_owner_id: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct TransferOwnerResponse {
pub member: TransferResult,
}
impl ApiResponseTrait for TransferOwnerResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
pub async fn transfer_owner(
request: TransferOwnerRequest,
config: &Config,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<TransferOwnerResponse>> {
let mut api_req = request.api_request;
api_req.http_method = Method::POST;
api_req.api_path = format!(
"{}?type={}",
EndpointBuilder::replace_param(
DRIVE_V1_PERMISSIONS_MEMBERS_TRANSFER_OWNER,
"token",
&request.token
),
request.obj_type
);
let mut query_params = Vec::new();
if let Some(remove_old_owner) = request.remove_old_owner {
query_params.push(format!("remove_old_owner={remove_old_owner}"));
}
if let Some(need_notification) = request.need_notification {
query_params.push(format!("need_notification={need_notification}"));
}
if !query_params.is_empty() {
api_req.api_path = format!("{}&{}", api_req.api_path, query_params.join("&"));
}
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 TransferResult {
pub fn has_transfer_time(&self) -> bool {
self.transfer_time.is_some()
}
pub fn has_old_owner_info(&self) -> bool {
self.old_owner_type.is_some() && self.old_owner_id.is_some()
}
pub fn transfer_time_formatted(&self) -> Option<String> {
self.transfer_time
.map(|timestamp| format!("转移时间: {timestamp}"))
}
pub fn new_owner_info(&self) -> String {
format!("新所有者: {} ({})", self.member_id, self.member_type)
}
pub fn old_owner_info(&self) -> Option<String> {
if let (Some(old_type), Some(old_id)) = (&self.old_owner_type, &self.old_owner_id) {
Some(format!("原所有者: {old_id} ({old_type})"))
} else {
None
}
}
pub fn summary(&self) -> String {
let mut parts = vec![self.new_owner_info()];
if let Some(old_info) = self.old_owner_info() {
parts.push(old_info);
}
if let Some(time_info) = self.transfer_time_formatted() {
parts.push(time_info);
}
parts.join(", ")
}
}
impl TransferOwnerResponse {
pub fn new_owner_id(&self) -> &str {
&self.member.member_id
}
pub fn new_owner_type(&self) -> &str {
&self.member.member_type
}
pub fn transfer_time(&self) -> Option<i64> {
self.member.transfer_time
}
pub fn is_transferred(&self) -> bool {
!self.member.member_id.is_empty()
}
pub fn success_summary(&self) -> String {
format!("所有者转移成功: {}", self.member.summary())
}
}
#[cfg(test)]
#[allow(unused_variables, unused_unsafe)]
mod tests {
use super::*;
#[test]
fn test_transfer_owner_request_builder() {
let request = TransferOwnerRequest::builder()
.token("doccnxxxxxx")
.as_doc()
.to_user("user123")
.remove_current_owner()
.with_notification()
.build();
assert_eq!(request.token, "doccnxxxxxx");
assert_eq!(request.obj_type, "doc");
assert_eq!(request.member_type, "user");
assert_eq!(request.member_id, "user123");
assert_eq!(request.remove_old_owner, Some(true));
assert_eq!(request.need_notification, Some(true));
}
#[test]
fn test_transfer_owner_convenience_method() {
let request = TransferOwnerRequest::to_user("doccnxxxxxx", "doc", "user123");
assert_eq!(request.member_type, "user");
assert_eq!(request.member_id, "user123");
}
}