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