open_lark/service/cloud_docs/permission/member/
transfer_owner.rs1use 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 req_option::RequestOption,
12 SDKResult,
13};
14
15#[derive(Debug, Serialize, Default, Clone)]
17pub struct TransferOwnerRequest {
18 #[serde(skip)]
19 api_request: ApiRequest,
20 #[serde(skip)]
22 token: String,
23 #[serde(skip)]
25 obj_type: String,
26 member_type: String,
28 member_id: String,
30 #[serde(skip_serializing_if = "Option::is_none")]
32 remove_old_owner: Option<bool>,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 need_notification: Option<bool>,
36}
37
38impl TransferOwnerRequest {
39 pub fn builder() -> TransferOwnerRequestBuilder {
40 TransferOwnerRequestBuilder::default()
41 }
42
43 pub fn new(
44 token: impl ToString,
45 obj_type: impl ToString,
46 member_type: impl ToString,
47 member_id: impl ToString,
48 ) -> Self {
49 Self {
50 token: token.to_string(),
51 obj_type: obj_type.to_string(),
52 member_type: member_type.to_string(),
53 member_id: member_id.to_string(),
54 ..Default::default()
55 }
56 }
57
58 pub fn to_user(token: impl ToString, obj_type: impl ToString, user_id: impl ToString) -> Self {
60 Self::new(token, obj_type, "user", user_id)
61 }
62}
63
64#[derive(Default)]
65pub struct TransferOwnerRequestBuilder {
66 request: TransferOwnerRequest,
67}
68
69impl TransferOwnerRequestBuilder {
70 pub fn token(mut self, token: impl ToString) -> Self {
72 self.request.token = token.to_string();
73 self
74 }
75
76 pub fn obj_type(mut self, obj_type: impl ToString) -> Self {
78 self.request.obj_type = obj_type.to_string();
79 self
80 }
81
82 pub fn as_doc(mut self) -> Self {
84 self.request.obj_type = "doc".to_string();
85 self
86 }
87
88 pub fn as_sheet(mut self) -> Self {
90 self.request.obj_type = "sheet".to_string();
91 self
92 }
93
94 pub fn as_bitable(mut self) -> Self {
96 self.request.obj_type = "bitable".to_string();
97 self
98 }
99
100 pub fn as_wiki(mut self) -> Self {
102 self.request.obj_type = "wiki".to_string();
103 self
104 }
105
106 pub fn new_owner(mut self, member_type: impl ToString, member_id: impl ToString) -> Self {
108 self.request.member_type = member_type.to_string();
109 self.request.member_id = member_id.to_string();
110 self
111 }
112
113 pub fn to_user(mut self, user_id: impl ToString) -> Self {
115 self.request.member_type = "user".to_string();
116 self.request.member_id = user_id.to_string();
117 self
118 }
119
120 pub fn to_chat(mut self, chat_id: impl ToString) -> Self {
122 self.request.member_type = "chat".to_string();
123 self.request.member_id = chat_id.to_string();
124 self
125 }
126
127 pub fn to_department(mut self, department_id: impl ToString) -> Self {
129 self.request.member_type = "department".to_string();
130 self.request.member_id = department_id.to_string();
131 self
132 }
133
134 pub fn remove_old_owner(mut self, remove: bool) -> Self {
136 self.request.remove_old_owner = Some(remove);
137 self
138 }
139
140 pub fn remove_current_owner(mut self) -> Self {
142 self.request.remove_old_owner = Some(true);
143 self
144 }
145
146 pub fn keep_current_owner(mut self) -> Self {
148 self.request.remove_old_owner = Some(false);
149 self
150 }
151
152 pub fn need_notification(mut self, need: bool) -> Self {
154 self.request.need_notification = Some(need);
155 self
156 }
157
158 pub fn with_notification(mut self) -> Self {
160 self.request.need_notification = Some(true);
161 self
162 }
163
164 pub fn without_notification(mut self) -> Self {
166 self.request.need_notification = Some(false);
167 self
168 }
169
170 pub fn build(mut self) -> TransferOwnerRequest {
171 self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
172 self.request
173 }
174}
175
176#[derive(Debug, Deserialize)]
178pub struct TransferResult {
179 pub member_type: String,
181 pub member_id: String,
183 pub transfer_time: Option<i64>,
185 pub old_owner_type: Option<String>,
187 pub old_owner_id: Option<String>,
189}
190
191#[derive(Debug, Deserialize)]
193pub struct TransferOwnerResponse {
194 pub member: TransferResult,
196}
197
198impl ApiResponseTrait for TransferOwnerResponse {
199 fn data_format() -> ResponseFormat {
200 ResponseFormat::Data
201 }
202}
203
204pub async fn transfer_owner(
206 request: TransferOwnerRequest,
207 config: &Config,
208 option: Option<RequestOption>,
209) -> SDKResult<BaseResponse<TransferOwnerResponse>> {
210 let mut api_req = request.api_request;
211 api_req.http_method = Method::POST;
212 api_req.api_path = format!(
213 "{}?type={}",
214 EndpointBuilder::replace_param(
215 DRIVE_V1_PERMISSIONS_MEMBERS_TRANSFER_OWNER,
216 "token",
217 &request.token
218 ),
219 request.obj_type
220 );
221
222 let mut query_params = Vec::new();
224 if let Some(remove_old_owner) = request.remove_old_owner {
225 query_params.push(format!("remove_old_owner={remove_old_owner}"));
226 }
227 if let Some(need_notification) = request.need_notification {
228 query_params.push(format!("need_notification={need_notification}"));
229 }
230
231 if !query_params.is_empty() {
232 api_req.api_path = format!("{}&{}", api_req.api_path, query_params.join("&"));
233 }
234
235 api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
236
237 let api_resp = Transport::request(api_req, config, option).await?;
238 Ok(api_resp)
239}
240
241impl TransferResult {
242 pub fn has_transfer_time(&self) -> bool {
244 self.transfer_time.is_some()
245 }
246
247 pub fn has_old_owner_info(&self) -> bool {
249 self.old_owner_type.is_some() && self.old_owner_id.is_some()
250 }
251
252 pub fn transfer_time_formatted(&self) -> Option<String> {
254 self.transfer_time
255 .map(|timestamp| format!("转移时间: {timestamp}"))
256 }
257
258 pub fn new_owner_info(&self) -> String {
260 format!("新所有者: {} ({})", self.member_id, self.member_type)
261 }
262
263 pub fn old_owner_info(&self) -> Option<String> {
265 if let (Some(old_type), Some(old_id)) = (&self.old_owner_type, &self.old_owner_id) {
266 Some(format!("原所有者: {old_id} ({old_type})"))
267 } else {
268 None
269 }
270 }
271
272 pub fn summary(&self) -> String {
274 let mut parts = vec![self.new_owner_info()];
275
276 if let Some(old_info) = self.old_owner_info() {
277 parts.push(old_info);
278 }
279
280 if let Some(time_info) = self.transfer_time_formatted() {
281 parts.push(time_info);
282 }
283
284 parts.join(", ")
285 }
286}
287
288impl TransferOwnerResponse {
289 pub fn new_owner_id(&self) -> &str {
291 &self.member.member_id
292 }
293
294 pub fn new_owner_type(&self) -> &str {
296 &self.member.member_type
297 }
298
299 pub fn transfer_time(&self) -> Option<i64> {
301 self.member.transfer_time
302 }
303
304 pub fn is_transferred(&self) -> bool {
306 !self.member.member_id.is_empty()
307 }
308
309 pub fn success_summary(&self) -> String {
311 format!("所有者转移成功: {}", self.member.summary())
312 }
313}
314
315#[cfg(test)]
316#[allow(unused_variables, unused_unsafe)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn test_transfer_owner_request_builder() {
322 let request = TransferOwnerRequest::builder()
323 .token("doccnxxxxxx")
324 .as_doc()
325 .to_user("user123")
326 .remove_current_owner()
327 .with_notification()
328 .build();
329
330 assert_eq!(request.token, "doccnxxxxxx");
331 assert_eq!(request.obj_type, "doc");
332 assert_eq!(request.member_type, "user");
333 assert_eq!(request.member_id, "user123");
334 assert_eq!(request.remove_old_owner, Some(true));
335 assert_eq!(request.need_notification, Some(true));
336 }
337
338 #[test]
339 fn test_transfer_owner_convenience_method() {
340 let request = TransferOwnerRequest::to_user("doccnxxxxxx", "doc", "user123");
341 assert_eq!(request.member_type, "user");
342 assert_eq!(request.member_id, "user123");
343 }
344}