use openlark_core::{
SDKResult,
api::{ApiRequest, ApiResponseTrait, ResponseFormat},
config::Config,
http::Transport,
validate_required,
};
use serde::{Deserialize, Serialize};
use crate::common::{api_endpoints::DriveApi, api_utils::*};
#[derive(Debug)]
pub struct UploadAllRequest {
config: Config,
pub file_name: String,
pub parent_node: String,
pub parent_type: String,
pub size: usize,
pub checksum: Option<String>,
pub file: Vec<u8>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UploadAllResponse {
pub file_token: String,
}
impl ApiResponseTrait for UploadAllResponse {
fn data_format() -> ResponseFormat {
ResponseFormat::Data
}
}
impl UploadAllRequest {
pub fn new(
config: Config,
file_name: impl Into<String>,
parent_node: impl Into<String>,
parent_type: impl Into<String>,
size: usize,
file: Vec<u8>,
) -> Self {
Self {
config,
file_name: file_name.into(),
parent_node: parent_node.into(),
parent_type: parent_type.into(),
size,
checksum: None,
file,
}
}
pub fn checksum(mut self, checksum: impl Into<String>) -> Self {
self.checksum = Some(checksum.into());
self
}
pub async fn execute(self) -> SDKResult<UploadAllResponse> {
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<UploadAllResponse> {
let file_name_len = self.file_name.chars().count();
if file_name_len == 0 || file_name_len > 250 {
return Err(openlark_core::error::validation_error(
"file_name",
"file_name 长度必须在 1~250 字符之间",
));
}
if self.parent_type != "explorer" {
return Err(openlark_core::error::validation_error(
"parent_type",
"parent_type 仅支持固定值 explorer",
));
}
validate_required!(self.parent_node, "parent_node 不能为空");
if self.size == 0 || self.size > 20 * 1024 * 1024 {
return Err(openlark_core::error::validation_error(
"size",
"size 必须在 1~20971520 字节之间",
));
}
if self.file.len() != self.size {
return Err(openlark_core::error::validation_error(
"size",
"size 必须与 file 的实际长度一致",
));
}
let api_endpoint = DriveApi::UploadFile;
#[derive(Serialize)]
struct UploadMeta {
file_name: String,
parent_type: String,
parent_node: String,
size: usize,
#[serde(skip_serializing_if = "Option::is_none")]
checksum: Option<String>,
}
let meta = UploadMeta {
file_name: self.file_name,
parent_type: self.parent_type,
parent_node: self.parent_node,
size: self.size,
checksum: self.checksum,
};
let request = ApiRequest::<UploadAllResponse>::post(&api_endpoint.to_url())
.json_body(&meta)
.file_content(self.file);
let response = Transport::request(request, &self.config, Some(option)).await?;
extract_response_data(response, "上传文件")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_upload_all_request() {
let config = Config::default();
let request =
UploadAllRequest::new(config, "test.txt", "folder_token", "explorer", 100, vec![]);
assert_eq!(request.file_name, "test.txt");
assert_eq!(request.parent_node, "folder_token");
assert_eq!(request.parent_type, "explorer");
}
#[test]
fn test_upload_all_with_checksum() {
let config = Config::default();
let file = vec![1, 2, 3, 4];
let request = UploadAllRequest::new(
config,
"test.txt",
"folder_token",
"explorer",
4,
file.clone(),
)
.checksum("abc123");
assert_eq!(request.checksum, Some("abc123".to_string()));
assert_eq!(request.file.len(), 4);
}
#[test]
fn test_upload_all_empty_file_name() {
let config = Config::default();
let request = UploadAllRequest::new(config, "", "folder_token", "explorer", 0, vec![]);
assert_eq!(request.file_name, "");
}
#[test]
fn test_upload_all_invalid_parent_type() {
let config = Config::default();
let request =
UploadAllRequest::new(config, "test.txt", "folder_token", "invalid", 100, vec![]);
assert_eq!(request.parent_type, "invalid");
}
#[test]
fn test_upload_all_empty_parent_node() {
let config = Config::default();
let request = UploadAllRequest::new(config, "test.txt", "", "explorer", 100, vec![]);
assert_eq!(request.parent_node, "");
}
#[test]
fn test_upload_all_max_file_size() {
let config = Config::default();
let max_size = 20 * 1024 * 1024; let file = vec![0; max_size];
let request = UploadAllRequest::new(
config,
"test.txt",
"folder_token",
"explorer",
max_size,
file,
);
assert_eq!(request.size, max_size);
assert_eq!(request.file.len(), max_size);
}
#[test]
fn test_upload_all_exceeds_max_size() {
let config = Config::default();
let too_large = 20 * 1024 * 1024 + 1; let request = UploadAllRequest::new(
config,
"test.txt",
"folder_token",
"explorer",
too_large,
vec![],
);
assert!(request.size > 20 * 1024 * 1024);
}
#[test]
fn test_upload_all_size_mismatch() {
let config = Config::default();
let file = vec![1, 2, 3]; let request =
UploadAllRequest::new(config, "test.txt", "folder_token", "explorer", 100, file);
assert_eq!(request.size, 100);
assert_eq!(request.file.len(), 3);
}
}