open_lark/service/contact/v3/
user.rs

1use crate::{
2    core::{
3        api_req::ApiRequest, api_resp::ApiResponseTrait, config::Config,
4        constants::AccessTokenType, http::Transport, req_option::RequestOption,
5        standard_response::StandardResponse, trait_system::executable_builder::ExecutableBuilder,
6        SDKResult,
7    },
8    service::contact::models::*,
9};
10use async_trait::async_trait;
11use serde::{Deserialize, Serialize};
12
13/// 用户管理服务
14///
15/// 提供完整的用户生命周期管理功能,包括:
16/// - 创建、更新、删除用户
17/// - 获取用户信息(单个/批量)
18/// - 搜索用户
19/// - 部门用户查询
20/// - 恢复已删除用户
21pub struct UserService {
22    config: Config,
23}
24
25impl UserService {
26    pub fn new(config: Config) -> Self {
27        Self { config }
28    }
29
30    /// 创建用户
31    pub async fn create(
32        &self,
33        req: &CreateUserRequest,
34    ) -> crate::core::SDKResult<CreateUserResponse> {
35        let api_req = ApiRequest {
36            http_method: reqwest::Method::POST,
37            api_path: "/open-apis/contact/v3/users".to_string(),
38            supported_access_token_types: vec![AccessTokenType::Tenant],
39            body: serde_json::to_vec(req)?,
40            ..Default::default()
41        };
42
43        let resp = Transport::<CreateUserResponse>::request(api_req, &self.config, None).await?;
44        resp.into_result()
45    }
46
47    /// 修改用户部分信息
48    pub async fn patch(
49        &self,
50        user_id: &str,
51        req: &PatchUserRequest,
52    ) -> crate::core::SDKResult<PatchUserResponse> {
53        let api_req = ApiRequest {
54            http_method: reqwest::Method::PATCH,
55            api_path: format!("/open-apis/contact/v3/users/{user_id}"),
56            supported_access_token_types: vec![AccessTokenType::Tenant],
57            body: serde_json::to_vec(req)?,
58            ..Default::default()
59        };
60
61        let resp = Transport::<PatchUserResponse>::request(api_req, &self.config, None).await?;
62        resp.into_result()
63    }
64
65    /// 更新用户 ID
66    pub async fn update_user_id(
67        &self,
68        user_id: &str,
69        req: &UpdateUserIdRequest,
70    ) -> crate::core::SDKResult<UpdateUserIdResponse> {
71        let api_req = ApiRequest {
72            http_method: reqwest::Method::PATCH,
73            api_path: format!("/open-apis/contact/v3/users/{user_id}/update_user_id"),
74            supported_access_token_types: vec![AccessTokenType::Tenant],
75            body: serde_json::to_vec(req)?,
76            ..Default::default()
77        };
78
79        let resp = Transport::<UpdateUserIdResponse>::request(api_req, &self.config, None).await?;
80        resp.into_result()
81    }
82
83    /// 获取单个用户信息
84    pub async fn get(
85        &self,
86        user_id: &str,
87        _req: &GetUserRequest,
88    ) -> crate::core::SDKResult<GetUserResponse> {
89        let api_req = ApiRequest {
90            http_method: reqwest::Method::GET,
91            api_path: format!("/open-apis/contact/v3/users/{user_id}"),
92            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
93            body: Vec::new(),
94            query_params: std::collections::HashMap::new(),
95            ..Default::default()
96        };
97
98        let resp = Transport::<GetUserResponse>::request(api_req, &self.config, None).await?;
99        resp.into_result()
100    }
101
102    /// 批量获取用户信息
103    pub async fn batch(
104        &self,
105        req: &BatchGetUsersRequest,
106    ) -> crate::core::SDKResult<BatchGetUsersResponse> {
107        let api_req = ApiRequest {
108            http_method: reqwest::Method::POST,
109            api_path: "/open-apis/contact/v3/users/batch".to_string(),
110            supported_access_token_types: vec![AccessTokenType::Tenant],
111            body: serde_json::to_vec(req)?,
112            ..Default::default()
113        };
114
115        let resp = Transport::<BatchGetUsersResponse>::request(api_req, &self.config, None).await?;
116        resp.into_result()
117    }
118
119    /// 获取部门直属用户列表
120    pub async fn find_by_department(
121        &self,
122        _req: &FindUsersByDepartmentRequest,
123    ) -> crate::core::SDKResult<FindUsersByDepartmentResponse> {
124        let api_req = ApiRequest {
125            http_method: reqwest::Method::GET,
126            api_path: "/open-apis/contact/v3/users/find_by_department".to_string(),
127            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
128            body: Vec::new(),
129            query_params: std::collections::HashMap::new(),
130            ..Default::default()
131        };
132
133        let resp = Transport::<FindUsersByDepartmentResponse>::request(api_req, &self.config, None)
134            .await?;
135        resp.into_result()
136    }
137
138    /// 通过手机号或邮箱获取用户 ID
139    pub async fn batch_get_id(
140        &self,
141        req: &BatchGetUserIdRequest,
142    ) -> crate::core::SDKResult<BatchGetUserIdResponse> {
143        let api_req = ApiRequest {
144            http_method: reqwest::Method::POST,
145            api_path: "/open-apis/contact/v3/users/batch_get_id".to_string(),
146            supported_access_token_types: vec![AccessTokenType::Tenant],
147            body: serde_json::to_vec(req)?,
148            ..Default::default()
149        };
150
151        let resp =
152            Transport::<BatchGetUserIdResponse>::request(api_req, &self.config, None).await?;
153        resp.into_result()
154    }
155
156    /// 搜索用户
157    pub async fn search(
158        &self,
159        req: &SearchUsersRequest,
160    ) -> crate::core::SDKResult<SearchUsersResponse> {
161        let api_req = ApiRequest {
162            http_method: reqwest::Method::POST,
163            api_path: "/open-apis/contact/v3/users/search".to_string(),
164            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
165            body: serde_json::to_vec(req)?,
166            ..Default::default()
167        };
168
169        let resp = Transport::<SearchUsersResponse>::request(api_req, &self.config, None).await?;
170        resp.into_result()
171    }
172
173    /// 删除用户
174    pub async fn delete(
175        &self,
176        user_id: &str,
177        _req: &DeleteUserRequest,
178    ) -> crate::core::SDKResult<DeleteUserResponse> {
179        let api_req = ApiRequest {
180            http_method: reqwest::Method::DELETE,
181            api_path: format!("/open-apis/contact/v3/users/{user_id}"),
182            supported_access_token_types: vec![AccessTokenType::Tenant],
183            body: Vec::new(),
184            query_params: std::collections::HashMap::new(),
185            ..Default::default()
186        };
187
188        let resp = Transport::<DeleteUserResponse>::request(api_req, &self.config, None).await?;
189        resp.into_result()
190    }
191
192    /// 恢复已删除用户
193    pub async fn resurrect(
194        &self,
195        user_id: &str,
196        req: &ResurrectUserRequest,
197    ) -> crate::core::SDKResult<ResurrectUserResponse> {
198        let api_req = ApiRequest {
199            http_method: reqwest::Method::POST,
200            api_path: format!("/open-apis/contact/v3/users/{user_id}/resurrect"),
201            supported_access_token_types: vec![AccessTokenType::Tenant],
202            body: serde_json::to_vec(req)?,
203            ..Default::default()
204        };
205
206        let resp = Transport::<ResurrectUserResponse>::request(api_req, &self.config, None).await?;
207        resp.into_result()
208    }
209
210    /// 获取用户列表
211    pub async fn list(&self, req: &ListUsersRequest) -> crate::core::SDKResult<ListUsersResponse> {
212        let mut query_params = std::collections::HashMap::new();
213
214        if let Some(page_size) = req.page_size {
215            query_params.insert("page_size".to_string(), page_size.to_string());
216        }
217        if let Some(page_token) = &req.page_token {
218            query_params.insert("page_token".to_string(), page_token.clone());
219        }
220        if let Some(user_id_type) = &req.user_id_type {
221            query_params.insert("user_id_type".to_string(), user_id_type.clone());
222        }
223        if let Some(department_id_type) = &req.department_id_type {
224            query_params.insert("department_id_type".to_string(), department_id_type.clone());
225        }
226
227        let api_req = ApiRequest {
228            http_method: reqwest::Method::GET,
229            api_path: "/open-apis/contact/v3/users".to_string(),
230            supported_access_token_types: vec![AccessTokenType::Tenant, AccessTokenType::User],
231            body: Vec::new(),
232            query_params,
233            ..Default::default()
234        };
235
236        let resp = Transport::<ListUsersResponse>::request(api_req, &self.config, None).await?;
237        resp.into_result()
238    }
239
240    /// 创建用户 - Builder模式 (推荐)
241    ///
242    /// 提供更现代化的Builder接口,支持链式调用和统一的执行模式
243    pub fn create_user_builder(&self) -> CreateUserBuilder {
244        CreateUserBuilder::new()
245    }
246}
247
248/// 创建用户的Builder
249#[derive(Default)]
250pub struct CreateUserBuilder {
251    user: Option<User>,
252    user_id_type: Option<String>,
253    department_id_type: Option<String>,
254}
255
256impl CreateUserBuilder {
257    pub fn new() -> Self {
258        Self::default()
259    }
260
261    /// 设置用户信息
262    pub fn user(mut self, user: User) -> Self {
263        self.user = Some(user);
264        self
265    }
266
267    /// 设置用户ID类型
268    pub fn user_id_type(mut self, user_id_type: impl ToString) -> Self {
269        self.user_id_type = Some(user_id_type.to_string());
270        self
271    }
272
273    /// 设置部门ID类型
274    pub fn department_id_type(mut self, department_id_type: impl ToString) -> Self {
275        self.department_id_type = Some(department_id_type.to_string());
276        self
277    }
278
279    pub fn build(self) -> CreateUserRequest {
280        CreateUserRequest {
281            user: self.user.unwrap_or_default(),
282            user_id_type: self.user_id_type,
283            department_id_type: self.department_id_type,
284        }
285    }
286}
287
288#[async_trait]
289impl ExecutableBuilder<UserService, CreateUserRequest, CreateUserResponse> for CreateUserBuilder {
290    fn build(self) -> CreateUserRequest {
291        self.build()
292    }
293
294    async fn execute(self, service: &UserService) -> SDKResult<CreateUserResponse> {
295        let req = self.build();
296        service.create(&req).await
297    }
298
299    async fn execute_with_options(
300        self,
301        service: &UserService,
302        _option: RequestOption,
303    ) -> SDKResult<CreateUserResponse> {
304        // 目前简单实现,后续可以支持传递option到service方法
305        let req = self.build();
306        service.create(&req).await
307    }
308}
309
310// 请求/响应结构体定义
311
312/// 创建用户请求
313#[derive(Debug, Clone, Serialize, Deserialize)]
314pub struct CreateUserRequest {
315    /// 用户信息
316    pub user: User,
317    /// 用户 ID 类型
318    #[serde(skip_serializing_if = "Option::is_none")]
319    pub user_id_type: Option<String>,
320    /// 部门 ID 类型
321    #[serde(skip_serializing_if = "Option::is_none")]
322    pub department_id_type: Option<String>,
323}
324
325/// 创建用户响应
326#[derive(Debug, Clone, Serialize, Deserialize, Default)]
327pub struct CreateUserResponse {
328    /// 用户信息
329    pub user: User,
330}
331
332impl ApiResponseTrait for CreateUserResponse {
333    fn data_format() -> crate::core::api_resp::ResponseFormat {
334        crate::core::api_resp::ResponseFormat::Data
335    }
336}
337
338/// 修改用户请求
339#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct PatchUserRequest {
341    /// 用户信息
342    pub user: User,
343    /// 用户 ID 类型
344    #[serde(skip_serializing_if = "Option::is_none")]
345    pub user_id_type: Option<String>,
346    /// 部门 ID 类型
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub department_id_type: Option<String>,
349}
350
351/// 修改用户响应
352#[derive(Debug, Clone, Serialize, Deserialize, Default)]
353pub struct PatchUserResponse {
354    /// 用户信息
355    pub user: User,
356}
357
358impl ApiResponseTrait for PatchUserResponse {
359    fn data_format() -> crate::core::api_resp::ResponseFormat {
360        crate::core::api_resp::ResponseFormat::Data
361    }
362}
363
364/// 更新用户ID请求
365#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct UpdateUserIdRequest {
367    /// 新的用户ID
368    pub new_user_id: String,
369    /// 用户 ID 类型
370    #[serde(skip_serializing_if = "Option::is_none")]
371    pub user_id_type: Option<String>,
372}
373
374/// 更新用户ID响应
375#[derive(Debug, Clone, Serialize, Deserialize, Default)]
376pub struct UpdateUserIdResponse {}
377
378impl ApiResponseTrait for UpdateUserIdResponse {
379    fn data_format() -> crate::core::api_resp::ResponseFormat {
380        crate::core::api_resp::ResponseFormat::Data
381    }
382}
383
384/// 获取用户请求
385#[derive(Debug, Clone, Default, Serialize, Deserialize)]
386pub struct GetUserRequest {
387    /// 用户 ID 类型
388    #[serde(skip_serializing_if = "Option::is_none")]
389    pub user_id_type: Option<String>,
390    /// 部门 ID 类型
391    #[serde(skip_serializing_if = "Option::is_none")]
392    pub department_id_type: Option<String>,
393}
394
395/// 获取用户响应
396#[derive(Debug, Clone, Serialize, Deserialize, Default)]
397pub struct GetUserResponse {
398    /// 用户信息
399    pub user: User,
400}
401
402impl ApiResponseTrait for GetUserResponse {
403    fn data_format() -> crate::core::api_resp::ResponseFormat {
404        crate::core::api_resp::ResponseFormat::Data
405    }
406}
407
408/// 批量获取用户请求
409#[derive(Debug, Clone, Serialize, Deserialize)]
410pub struct BatchGetUsersRequest {
411    /// 用户ID列表
412    pub user_ids: Vec<String>,
413    /// 用户 ID 类型
414    #[serde(skip_serializing_if = "Option::is_none")]
415    pub user_id_type: Option<String>,
416    /// 部门 ID 类型
417    #[serde(skip_serializing_if = "Option::is_none")]
418    pub department_id_type: Option<String>,
419}
420
421/// 批量获取用户响应
422#[derive(Debug, Clone, Serialize, Deserialize, Default)]
423pub struct BatchGetUsersResponse {
424    /// 用户列表
425    pub items: Vec<User>,
426}
427
428impl ApiResponseTrait for BatchGetUsersResponse {
429    fn data_format() -> crate::core::api_resp::ResponseFormat {
430        crate::core::api_resp::ResponseFormat::Data
431    }
432}
433
434/// 按部门查找用户请求
435#[derive(Debug, Clone, Default, Serialize, Deserialize)]
436pub struct FindUsersByDepartmentRequest {
437    /// 部门ID
438    #[serde(skip_serializing_if = "Option::is_none")]
439    pub department_id: Option<String>,
440    /// 用户 ID 类型
441    #[serde(skip_serializing_if = "Option::is_none")]
442    pub user_id_type: Option<String>,
443    /// 部门 ID 类型
444    #[serde(skip_serializing_if = "Option::is_none")]
445    pub department_id_type: Option<String>,
446    /// 分页大小
447    #[serde(skip_serializing_if = "Option::is_none")]
448    pub page_size: Option<i32>,
449    /// 分页标记
450    #[serde(skip_serializing_if = "Option::is_none")]
451    pub page_token: Option<String>,
452}
453
454/// 按部门查找用户响应
455#[derive(Debug, Clone, Serialize, Deserialize, Default)]
456pub struct FindUsersByDepartmentResponse {
457    /// 用户列表
458    pub items: Vec<User>,
459    /// 是否还有更多项目
460    #[serde(skip_serializing_if = "Option::is_none")]
461    pub has_more: Option<bool>,
462    /// 分页标记
463    #[serde(skip_serializing_if = "Option::is_none")]
464    pub page_token: Option<String>,
465}
466
467impl ApiResponseTrait for FindUsersByDepartmentResponse {
468    fn data_format() -> crate::core::api_resp::ResponseFormat {
469        crate::core::api_resp::ResponseFormat::Data
470    }
471}
472
473/// 批量获取用户ID请求
474#[derive(Debug, Clone, Serialize, Deserialize)]
475pub struct BatchGetUserIdRequest {
476    /// 邮箱列表
477    #[serde(skip_serializing_if = "Option::is_none")]
478    pub emails: Option<Vec<String>>,
479    /// 手机号列表
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub mobiles: Option<Vec<String>>,
482    /// 包含已离职用户
483    #[serde(skip_serializing_if = "Option::is_none")]
484    pub include_resigned: Option<bool>,
485}
486
487/// 批量获取用户ID响应
488#[derive(Debug, Clone, Serialize, Deserialize, Default)]
489pub struct BatchGetUserIdResponse {
490    /// 用户列表
491    pub user_list: Vec<UserIdInfo>,
492}
493
494impl ApiResponseTrait for BatchGetUserIdResponse {
495    fn data_format() -> crate::core::api_resp::ResponseFormat {
496        crate::core::api_resp::ResponseFormat::Data
497    }
498}
499
500/// 用户ID信息
501#[derive(Debug, Clone, Serialize, Deserialize)]
502pub struct UserIdInfo {
503    /// 用户ID
504    #[serde(skip_serializing_if = "Option::is_none")]
505    pub user_id: Option<String>,
506    /// 邮箱
507    #[serde(skip_serializing_if = "Option::is_none")]
508    pub email: Option<String>,
509    /// 手机号
510    #[serde(skip_serializing_if = "Option::is_none")]
511    pub mobile: Option<String>,
512}
513
514/// 搜索用户请求
515#[derive(Debug, Clone, Serialize, Deserialize)]
516pub struct SearchUsersRequest {
517    /// 搜索关键词
518    pub query: String,
519    /// 分页大小
520    #[serde(skip_serializing_if = "Option::is_none")]
521    pub page_size: Option<i32>,
522    /// 分页标记
523    #[serde(skip_serializing_if = "Option::is_none")]
524    pub page_token: Option<String>,
525    /// 用户 ID 类型
526    #[serde(skip_serializing_if = "Option::is_none")]
527    pub user_id_type: Option<String>,
528    /// 部门 ID 类型
529    #[serde(skip_serializing_if = "Option::is_none")]
530    pub department_id_type: Option<String>,
531}
532
533/// 搜索用户响应
534#[derive(Debug, Clone, Serialize, Deserialize, Default)]
535pub struct SearchUsersResponse {
536    /// 用户列表
537    pub items: Vec<User>,
538    /// 是否还有更多项目
539    #[serde(skip_serializing_if = "Option::is_none")]
540    pub has_more: Option<bool>,
541    /// 分页标记
542    #[serde(skip_serializing_if = "Option::is_none")]
543    pub page_token: Option<String>,
544}
545
546impl ApiResponseTrait for SearchUsersResponse {
547    fn data_format() -> crate::core::api_resp::ResponseFormat {
548        crate::core::api_resp::ResponseFormat::Data
549    }
550}
551
552/// 删除用户请求
553#[derive(Debug, Clone, Default, Serialize, Deserialize)]
554pub struct DeleteUserRequest {
555    /// 用户 ID 类型
556    #[serde(skip_serializing_if = "Option::is_none")]
557    pub user_id_type: Option<String>,
558    /// 部门 ID 类型
559    #[serde(skip_serializing_if = "Option::is_none")]
560    pub department_id_type: Option<String>,
561}
562
563/// 删除用户响应
564#[derive(Debug, Clone, Serialize, Deserialize, Default)]
565pub struct DeleteUserResponse {}
566
567impl ApiResponseTrait for DeleteUserResponse {
568    fn data_format() -> crate::core::api_resp::ResponseFormat {
569        crate::core::api_resp::ResponseFormat::Data
570    }
571}
572
573/// 恢复用户请求
574#[derive(Debug, Clone, Serialize, Deserialize)]
575pub struct ResurrectUserRequest {
576    /// 用户 ID 类型
577    #[serde(skip_serializing_if = "Option::is_none")]
578    pub user_id_type: Option<String>,
579    /// 部门 ID 类型
580    #[serde(skip_serializing_if = "Option::is_none")]
581    pub department_id_type: Option<String>,
582}
583
584/// 恢复用户响应
585#[derive(Debug, Clone, Serialize, Deserialize, Default)]
586pub struct ResurrectUserResponse {
587    /// 用户信息
588    pub user: User,
589}
590
591impl ApiResponseTrait for ResurrectUserResponse {
592    fn data_format() -> crate::core::api_resp::ResponseFormat {
593        crate::core::api_resp::ResponseFormat::Data
594    }
595}
596
597/// 获取用户列表请求
598#[derive(Debug, Clone, Default, Serialize, Deserialize)]
599pub struct ListUsersRequest {
600    /// 分页大小
601    #[serde(skip_serializing_if = "Option::is_none")]
602    pub page_size: Option<i32>,
603    /// 分页标记
604    #[serde(skip_serializing_if = "Option::is_none")]
605    pub page_token: Option<String>,
606    /// 用户 ID 类型
607    #[serde(skip_serializing_if = "Option::is_none")]
608    pub user_id_type: Option<String>,
609    /// 部门 ID 类型
610    #[serde(skip_serializing_if = "Option::is_none")]
611    pub department_id_type: Option<String>,
612}
613
614/// 获取用户列表响应
615#[derive(Debug, Clone, Serialize, Deserialize, Default)]
616pub struct ListUsersResponse {
617    /// 用户列表
618    pub items: Vec<User>,
619    /// 是否还有更多项目
620    #[serde(skip_serializing_if = "Option::is_none")]
621    pub has_more: Option<bool>,
622    /// 分页标记
623    #[serde(skip_serializing_if = "Option::is_none")]
624    pub page_token: Option<String>,
625}
626
627impl ApiResponseTrait for ListUsersResponse {
628    fn data_format() -> crate::core::api_resp::ResponseFormat {
629        crate::core::api_resp::ResponseFormat::Data
630    }
631}