open_lark/service/cloud_docs/wiki/v2/
search_wiki.rs1use reqwest::Method;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5 core::{
6 api_req::ApiRequest,
7 api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
8 config::Config,
9 constants::AccessTokenType,
10 endpoints::cloud_docs::*,
11 http::Transport,
12 req_option::RequestOption,
13 SDKResult,
14 },
15 impl_executable_builder_owned,
16};
17
18#[derive(Debug, Serialize, Default)]
20pub struct SearchWikiRequest {
21 #[serde(skip)]
22 api_request: ApiRequest,
23 query: String,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 page_size: Option<i32>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 page_token: Option<String>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 space_ids: Option<Vec<String>>,
34}
35
36impl SearchWikiRequest {
37 pub fn builder() -> SearchWikiRequestBuilder {
38 SearchWikiRequestBuilder::default()
39 }
40
41 pub fn new(query: impl ToString) -> Self {
42 Self {
43 query: query.to_string(),
44 ..Default::default()
45 }
46 }
47}
48
49#[derive(Default)]
50pub struct SearchWikiRequestBuilder {
51 request: SearchWikiRequest,
52}
53
54impl SearchWikiRequestBuilder {
55 pub fn query(mut self, query: impl ToString) -> Self {
57 self.request.query = query.to_string();
58 self
59 }
60
61 pub fn page_size(mut self, page_size: i32) -> Self {
63 self.request.page_size = Some(page_size);
64 self
65 }
66
67 pub fn page_token(mut self, page_token: impl ToString) -> Self {
69 self.request.page_token = Some(page_token.to_string());
70 self
71 }
72
73 pub fn space_ids(mut self, space_ids: Vec<String>) -> Self {
75 self.request.space_ids = Some(space_ids);
76 self
77 }
78
79 pub fn add_space_id(mut self, space_id: impl ToString) -> Self {
81 if self.request.space_ids.is_none() {
82 self.request.space_ids = Some(Vec::new());
83 }
84 if let Some(ref mut space_ids) = self.request.space_ids {
85 space_ids.push(space_id.to_string());
86 }
87 self
88 }
89
90 pub fn search_all_spaces(mut self) -> Self {
92 self.request.space_ids = None;
93 self
94 }
95
96 pub fn build(mut self) -> SearchWikiRequest {
97 self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
98 self.request
99 }
100}
101
102impl_executable_builder_owned!(
103 SearchWikiRequestBuilder,
104 crate::service::cloud_docs::wiki::v2::V2,
105 SearchWikiRequest,
106 SearchWikiResponse,
107 search_wiki
108);
109
110#[derive(Debug, Deserialize)]
112pub struct WikiSearchItem {
113 pub node_token: String,
115 pub space_id: String,
117 pub title: Option<String>,
119 pub obj_type: Option<String>,
121 pub obj_token: Option<String>,
123 pub parent_node_token: Option<String>,
125 pub space_name: Option<String>,
127 pub snippet: Option<String>,
129 pub obj_edit_time: Option<String>,
131 pub obj_edit_user: Option<String>,
133}
134
135#[derive(Debug, Deserialize)]
137pub struct SearchWikiResponse {
138 pub has_more: bool,
140 pub page_token: Option<String>,
142 pub items: Vec<WikiSearchItem>,
144}
145
146impl ApiResponseTrait for SearchWikiResponse {
147 fn data_format() -> ResponseFormat {
148 ResponseFormat::Data
149 }
150}
151
152pub async fn search_wiki(
154 request: SearchWikiRequest,
155 config: &Config,
156 option: Option<RequestOption>,
157) -> SDKResult<BaseResponse<SearchWikiResponse>> {
158 let mut api_req = request.api_request;
159 api_req.http_method = Method::POST;
160 api_req.api_path = WIKI_V2_SEARCH.to_string();
161 api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
162
163 let api_resp = Transport::request(api_req, config, option).await?;
164 Ok(api_resp)
165}
166
167impl WikiSearchItem {
168 pub fn get_doc_url(&self) -> Option<String> {
170 self.obj_token
171 .as_ref()
172 .map(|token| match self.obj_type.as_deref() {
173 Some("doc") => format!("https://feishu.cn/docs/{token}"),
174 Some("sheet") => format!("https://feishu.cn/sheets/{token}"),
175 Some("bitable") => format!("https://feishu.cn/base/{token}"),
176 Some("mindnote") => format!("https://feishu.cn/mindnote/{token}"),
177 _ => format!("https://feishu.cn/wiki/{token}"),
178 })
179 }
180
181 pub fn has_snippet(&self) -> bool {
183 self.snippet.is_some()
184 }
185
186 pub fn display_title(&self) -> String {
188 self.title.as_ref().cloned().unwrap_or_else(|| {
189 self.obj_token
190 .as_ref()
191 .cloned()
192 .unwrap_or_else(|| self.node_token.clone())
193 })
194 }
195}
196
197#[cfg(test)]
198#[allow(unused_variables, unused_unsafe)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn test_search_wiki_request_builder() {
204 let request = SearchWikiRequest::builder()
205 .query("测试搜索")
206 .page_size(20)
207 .add_space_id("spcxxxxxx")
208 .add_space_id("spcyyyyyy")
209 .build();
210
211 assert_eq!(request.query, "测试搜索");
212 assert_eq!(request.page_size, Some(20));
213 assert_eq!(
214 request.space_ids,
215 Some(vec!["spcxxxxxx".to_string(), "spcyyyyyy".to_string()])
216 );
217 }
218
219 #[test]
220 fn test_search_all_spaces() {
221 let request = SearchWikiRequest::builder()
222 .query("测试搜索")
223 .search_all_spaces()
224 .build();
225
226 assert_eq!(request.query, "测试搜索");
227 assert_eq!(request.space_ids, None);
228 }
229
230 #[test]
231 fn test_wiki_search_item_methods() {
232 let item = WikiSearchItem {
233 node_token: "wikcnxxxxxx".to_string(),
234 space_id: "spcxxxxxx".to_string(),
235 title: Some("测试文档".to_string()),
236 obj_type: Some("doc".to_string()),
237 obj_token: Some("doccnxxxxxx".to_string()),
238 parent_node_token: None,
239 space_name: Some("测试空间".to_string()),
240 snippet: Some("这是匹配的文本片段".to_string()),
241 obj_edit_time: None,
242 obj_edit_user: None,
243 };
244
245 assert_eq!(item.display_title(), "测试文档");
246 assert!(item.has_snippet());
247 assert_eq!(
248 item.get_doc_url(),
249 Some("https://feishu.cn/docs/doccnxxxxxx".to_string())
250 );
251 }
252}