use reqwest::Method;
use serde::{Deserialize, Serialize};
use crate::{
core::{
api_req::ApiRequest,
api_resp::{ApiResponseTrait, BaseResponse, ResponseFormat},
config::Config,
constants::AccessTokenType,
endpoints::cloud_docs::*,
http::Transport,
req_option::RequestOption,
SDKResult,
},
impl_executable_builder_owned,
};
#[derive(Debug, Serialize, Default)]
pub struct SearchWikiRequest {
#[serde(skip)]
api_request: ApiRequest,
query: String,
#[serde(skip_serializing_if = "Option::is_none")]
page_size: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
page_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
space_ids: Option<Vec<String>>,
}
impl SearchWikiRequest {
pub fn builder() -> SearchWikiRequestBuilder {
SearchWikiRequestBuilder::default()
}
pub fn new(query: impl ToString) -> Self {
Self {
query: query.to_string(),
..Default::default()
}
}
}
#[derive(Default)]
pub struct SearchWikiRequestBuilder {
request: SearchWikiRequest,
}
impl SearchWikiRequestBuilder {
pub fn query(mut self, query: impl ToString) -> Self {
self.request.query = query.to_string();
self
}
pub fn page_size(mut self, page_size: i32) -> Self {
self.request.page_size = Some(page_size);
self
}
pub fn page_token(mut self, page_token: impl ToString) -> Self {
self.request.page_token = Some(page_token.to_string());
self
}
pub fn space_ids(mut self, space_ids: Vec<String>) -> Self {
self.request.space_ids = Some(space_ids);
self
}
pub fn add_space_id(mut self, space_id: impl ToString) -> Self {
if self.request.space_ids.is_none() {
self.request.space_ids = Some(Vec::new());
}
if let Some(ref mut space_ids) = self.request.space_ids {
space_ids.push(space_id.to_string());
}
self
}
pub fn search_all_spaces(mut self) -> Self {
self.request.space_ids = None;
self
}
pub fn build(mut self) -> SearchWikiRequest {
self.request.api_request.body = serde_json::to_vec(&self.request).unwrap();
self.request
}
}
impl_executable_builder_owned!(
SearchWikiRequestBuilder,
crate::service::cloud_docs::wiki::v2::V2,
SearchWikiRequest,
SearchWikiResponse,
search_wiki
);
#[derive(Debug, Deserialize)]
pub struct WikiSearchItem {
pub node_token: String,
pub space_id: String,
pub title: Option<String>,
pub obj_type: Option<String>,
pub obj_token: Option<String>,
pub parent_node_token: Option<String>,
pub space_name: Option<String>,
pub snippet: Option<String>,
pub obj_edit_time: Option<String>,
pub obj_edit_user: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct SearchWikiResponse {
pub has_more: bool,
pub page_token: Option<String>,
pub items: Vec<WikiSearchItem>,
}
impl ApiResponseTrait for SearchWikiResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
pub async fn search_wiki(
request: SearchWikiRequest,
config: &Config,
option: Option<RequestOption>,
) -> SDKResult<BaseResponse<SearchWikiResponse>> {
let mut api_req = request.api_request;
api_req.http_method = Method::POST;
api_req.api_path = WIKI_V2_SEARCH.to_string();
api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
let api_resp = Transport::request(api_req, config, option).await?;
Ok(api_resp)
}
impl WikiSearchItem {
pub fn get_doc_url(&self) -> Option<String> {
self.obj_token
.as_ref()
.map(|token| match self.obj_type.as_deref() {
Some("doc") => format!("https://feishu.cn/docs/{token}"),
Some("sheet") => format!("https://feishu.cn/sheets/{token}"),
Some("bitable") => format!("https://feishu.cn/base/{token}"),
Some("mindnote") => format!("https://feishu.cn/mindnote/{token}"),
_ => format!("https://feishu.cn/wiki/{token}"),
})
}
pub fn has_snippet(&self) -> bool {
self.snippet.is_some()
}
pub fn display_title(&self) -> String {
self.title.as_ref().cloned().unwrap_or_else(|| {
self.obj_token
.as_ref()
.cloned()
.unwrap_or_else(|| self.node_token.clone())
})
}
}
#[cfg(test)]
#[allow(unused_variables, unused_unsafe)]
mod tests {
use super::*;
#[test]
fn test_search_wiki_request_builder() {
let request = SearchWikiRequest::builder()
.query("测试搜索")
.page_size(20)
.add_space_id("spcxxxxxx")
.add_space_id("spcyyyyyy")
.build();
assert_eq!(request.query, "测试搜索");
assert_eq!(request.page_size, Some(20));
assert_eq!(
request.space_ids,
Some(vec!["spcxxxxxx".to_string(), "spcyyyyyy".to_string()])
);
}
#[test]
fn test_search_all_spaces() {
let request = SearchWikiRequest::builder()
.query("测试搜索")
.search_all_spaces()
.build();
assert_eq!(request.query, "测试搜索");
assert_eq!(request.space_ids, None);
}
#[test]
fn test_wiki_search_item_methods() {
let item = WikiSearchItem {
node_token: "wikcnxxxxxx".to_string(),
space_id: "spcxxxxxx".to_string(),
title: Some("测试文档".to_string()),
obj_type: Some("doc".to_string()),
obj_token: Some("doccnxxxxxx".to_string()),
parent_node_token: None,
space_name: Some("测试空间".to_string()),
snippet: Some("这是匹配的文本片段".to_string()),
obj_edit_time: None,
obj_edit_user: None,
};
assert_eq!(item.display_title(), "测试文档");
assert!(item.has_snippet());
assert_eq!(
item.get_doc_url(),
Some("https://feishu.cn/docs/doccnxxxxxx".to_string())
);
}
}