open_lark/service/search/v1/
user.rs

1use log::error;
2use reqwest::Method;
3use serde::{Deserialize, Serialize};
4
5use crate::core::{
6    api_req::ApiRequest,
7    api_resp::{ApiResponseTrait, BaseResponse},
8    config::Config,
9    constants::AccessTokenType,
10    http::Transport,
11    req_option::RequestOption,
12    SDKResult,
13};
14
15pub struct UserService {
16    config: Config,
17}
18
19impl UserService {
20    pub fn new(config: Config) -> Self {
21        Self { config }
22    }
23
24    /// 搜索用户
25    ///
26    /// <https://open.feishu.cn/document/server-docs/search-v1/user/search>
27    pub async fn search_user(
28        &self,
29        search_user_request: SearchUserRequest,
30        option: Option<RequestOption>,
31    ) -> SDKResult<BaseResponse<SearchUserResponse>> {
32        let mut api_req = search_user_request.api_request;
33        api_req.http_method = Method::GET;
34        api_req.api_path = "/open-apis/search/v1/user".to_string();
35        api_req.supported_access_token_types = vec![AccessTokenType::User];
36
37        let api_resp = Transport::request(api_req, &self.config, option).await?;
38
39        Ok(api_resp)
40    }
41
42    pub fn search_user_iter(
43        &self,
44        search_user_request: SearchUserRequest,
45        option: Option<RequestOption>,
46    ) -> SearchUserIterator<'_> {
47        SearchUserIterator {
48            user_service: self,
49            request: search_user_request,
50            option,
51            has_more: true,
52        }
53    }
54}
55
56/// 搜索用户请求
57#[derive(Default, Clone)]
58pub struct SearchUserRequest {
59    api_request: ApiRequest,
60}
61
62impl SearchUserRequest {
63    pub fn builder() -> SearchUserRequestBuilder {
64        SearchUserRequestBuilder::default()
65    }
66}
67
68#[derive(Default)]
69pub struct SearchUserRequestBuilder {
70    search_user_request: SearchUserRequest,
71}
72
73impl SearchUserRequestBuilder {
74    /// 要执行搜索的字符串,一般为用户名。
75    pub fn query(mut self, query: impl ToString) -> Self {
76        self.search_user_request
77            .api_request
78            .query_params
79            .insert("query".to_string(), query.to_string());
80        self
81    }
82
83    /// 分页大小,最小为 1,最大为 200,默认为 20。
84    pub fn page_size(mut self, page_size: i32) -> Self {
85        self.search_user_request
86            .api_request
87            .query_params
88            .insert("page_size".to_string(), page_size.to_string());
89        self
90    }
91
92    /// 分页标识,获取首页不需要填写,获取下一页时传入上一页返回的分页标识值。
93    /// 请注意此字段的值并没有特殊含义,请使用每次请求所返回的标识值。
94    pub fn page_token(mut self, page_token: impl ToString) -> Self {
95        self.search_user_request
96            .api_request
97            .query_params
98            .insert("page_token".to_string(), page_token.to_string());
99        self
100    }
101
102    pub fn build(self) -> SearchUserRequest {
103        self.search_user_request
104    }
105}
106
107crate::impl_executable_builder_owned!(
108    SearchUserRequestBuilder,
109    UserService,
110    SearchUserRequest,
111    BaseResponse<SearchUserResponse>,
112    search_user
113);
114
115#[derive(Debug, Serialize, Deserialize)]
116pub struct SearchUserResponse {
117    /// 搜索到的用户列表。
118    pub users: Vec<UserInSearchResponse>,
119    /// 是否还有更多用户,值为 true 表示存在下一页。
120    pub has_more: bool,
121    /// 分页标识,存在下一页的时候返回。下次请求带上此标识可以获取下一页的用户。
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub page_token: Option<String>,
124}
125
126/// 搜索到的用户信息。
127#[derive(Debug, Serialize, Deserialize)]
128pub struct UserInSearchResponse {
129    /// 用户的头像 URL。
130    pub avatar: UserAvatar,
131    /// 用户的部门信息。
132    pub department_ids: Vec<String>,
133    /// 用户的姓名。
134    pub name: String,
135    /// 用户的 open_id。
136    pub open_id: String,
137    /// 用户的 open_id。
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub user_id: Option<String>,
140}
141
142/// 用户的头像信息。
143#[derive(Debug, Serialize, Deserialize)]
144pub struct UserAvatar {
145    /// 用户的头像图片 URL,72×72px。
146    pub avatar_72: String,
147    /// 用户的头像图片 URL,240×240px。
148    pub avatar_240: String,
149    /// 用户的头像图片 URL,640×640px。
150    pub avatar_640: String,
151    /// 用户的头像图片 URL,原始大小。
152    pub avatar_origin: String,
153}
154
155impl ApiResponseTrait for SearchUserResponse {
156    fn data_format() -> crate::core::api_resp::ResponseFormat {
157        crate::core::api_resp::ResponseFormat::Data
158    }
159}
160
161pub struct SearchUserIterator<'a> {
162    user_service: &'a UserService,
163    request: SearchUserRequest,
164    option: Option<RequestOption>,
165    has_more: bool,
166}
167
168impl SearchUserIterator<'_> {
169    pub async fn next(&mut self) -> Option<Vec<UserInSearchResponse>> {
170        if !self.has_more {
171            return None;
172        }
173
174        match self
175            .user_service
176            .search_user(self.request.clone(), self.option.clone())
177            .await
178        {
179            Ok(resp) => match resp.data {
180                Some(data) => {
181                    self.has_more = data.has_more;
182                    if data.has_more {
183                        self.request
184                            .api_request
185                            .query_params
186                            .insert("page_token".to_string(), data.page_token.unwrap());
187                        Some(data.users)
188                    } else if data.users.is_empty() {
189                        None
190                    } else {
191                        Some(data.users)
192                    }
193                }
194                None => None,
195            },
196            Err(e) => {
197                error!("Error: {e:?}");
198                None
199            }
200        }
201    }
202}