use openlark_core::{
SDKResult,
api::{ApiRequest, ApiResponseTrait, ResponseFormat},
config::Config,
http::Transport,
};
use serde::{Deserialize, Serialize};
use crate::common::{api_endpoints::DriveApi, api_utils::*};
#[derive(Debug)]
pub struct ListFilesRequest {
config: Config,
pub folder_token: Option<String>,
pub page_size: Option<i32>,
pub page_token: Option<String>,
pub order_by: Option<String>,
pub direction: Option<String>,
pub user_id_type: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileInfo {
pub token: String,
pub name: String,
pub r#type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_token: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shortcut_info: Option<ShortcutInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub modified_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub owner_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ShortcutInfo {
pub target_type: String,
pub target_token: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListFilesResponse {
pub files: Vec<FileInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_page_token: Option<String>,
pub has_more: bool,
}
impl ApiResponseTrait for ListFilesResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
impl ListFilesRequest {
pub fn new(config: Config) -> Self {
Self {
config,
folder_token: None,
page_size: None,
page_token: None,
order_by: None,
direction: None,
user_id_type: None,
}
}
pub fn folder_token(mut self, folder_token: impl Into<String>) -> Self {
self.folder_token = Some(folder_token.into());
self
}
pub fn page_size(mut self, page_size: i32) -> Self {
self.page_size = Some(page_size);
self
}
pub fn page_token(mut self, page_token: impl Into<String>) -> Self {
self.page_token = Some(page_token.into());
self
}
pub fn order_by(mut self, order_by: impl Into<String>) -> Self {
self.order_by = Some(order_by.into());
self
}
pub fn direction(mut self, direction: impl Into<String>) -> Self {
self.direction = Some(direction.into());
self
}
pub fn user_id_type(mut self, user_id_type: impl Into<String>) -> Self {
self.user_id_type = Some(user_id_type.into());
self
}
pub async fn execute(self) -> SDKResult<ListFilesResponse> {
self.execute_with_options(openlark_core::req_option::RequestOption::default())
.await
}
pub async fn execute_with_options(
self,
option: openlark_core::req_option::RequestOption,
) -> SDKResult<ListFilesResponse> {
let is_root = self
.folder_token
.as_deref()
.map(|t| t.trim().is_empty())
.unwrap_or(true);
if is_root {
if self.page_size.is_some() {
return Err(openlark_core::error::validation_error(
"page_size",
"获取根目录清单时不支持分页,请勿传入 page_size",
));
}
if self.page_token.is_some() {
return Err(openlark_core::error::validation_error(
"page_token",
"获取根目录清单时不支持分页,请勿传入 page_token",
));
}
}
if let Some(page_size) = self.page_size
&& !(1..=200).contains(&page_size)
{
return Err(openlark_core::error::validation_error(
"page_size",
"page_size 必须在 1~200 之间",
));
}
if let Some(order_by) = &self.order_by {
match order_by.as_str() {
"EditedTime" | "CreatedTime" => {}
_ => {
return Err(openlark_core::error::validation_error(
"order_by",
"order_by 仅支持 EditedTime/CreatedTime",
));
}
}
}
if let Some(direction) = &self.direction {
match direction.as_str() {
"ASC" | "DESC" => {}
_ => {
return Err(openlark_core::error::validation_error(
"direction",
"direction 仅支持 ASC/DESC",
));
}
}
}
if let Some(user_id_type) = &self.user_id_type {
match user_id_type.as_str() {
"open_id" | "union_id" | "user_id" => {}
_ => {
return Err(openlark_core::error::validation_error(
"user_id_type",
"user_id_type 仅支持 open_id/union_id/user_id",
));
}
}
}
let api_endpoint = DriveApi::ListFiles;
let mut request = ApiRequest::<ListFilesResponse>::get(&api_endpoint.to_url());
if let Some(token) = &self.folder_token {
request = request.query("folder_token", token);
}
if let Some(size) = self.page_size {
request = request.query("page_size", size.to_string());
}
if let Some(token) = &self.page_token {
request = request.query("page_token", token);
}
if let Some(order) = &self.order_by {
request = request.query("order_by", order);
}
if let Some(direction) = &self.direction {
request = request.query("direction", direction);
}
if let Some(user_id_type) = &self.user_id_type {
request = request.query("user_id_type", user_id_type);
}
let response = Transport::request(request, &self.config, Some(option)).await?;
extract_response_data(response, "获取文件夹中的文件清单")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_list_files_request_builder() {
let config = Config::default();
let request = ListFilesRequest::new(config)
.folder_token("folder_token")
.page_size(50)
.order_by("EditedTime")
.direction("DESC")
.user_id_type("open_id");
assert_eq!(request.folder_token, Some("folder_token".to_string()));
assert_eq!(request.page_size, Some(50));
assert_eq!(request.order_by, Some("EditedTime".to_string()));
assert_eq!(request.direction, Some("DESC".to_string()));
assert_eq!(request.user_id_type, Some("open_id".to_string()));
}
#[test]
fn test_list_files_request_root() {
let config = Config::default();
let request = ListFilesRequest::new(config);
assert_eq!(request.folder_token, None);
assert_eq!(request.page_token, None);
}
#[test]
fn test_response_trait() {
assert_eq!(ListFilesResponse::data_format(), ResponseFormat::Data);
}
}