use reqwest::Client;
use crate::types::{DriveError, DriveFile, FileList};
const FILES_ENDPOINT: &str = "https://www.googleapis.com/drive/v3/files";
const DEFAULT_FIELDS: &str =
"files(id,name,mimeType,size,createdTime,modifiedTime,parents,shared,webViewLink,owners,permissions,trashed),nextPageToken";
#[derive(Default)]
pub struct ListOptions {
pub parent_id: Option<String>,
pub query: Option<String>,
pub page_size: Option<u32>,
pub page_token: Option<String>,
pub include_trashed: bool,
pub order_by: Option<String>,
}
pub async fn list_files(
client: &Client,
access_token: &str,
opts: &ListOptions,
) -> Result<FileList, DriveError> {
let mut q_parts: Vec<String> = Vec::new();
if let Some(parent) = &opts.parent_id {
q_parts.push(format!("'{}' in parents", parent));
}
if !opts.include_trashed {
q_parts.push("trashed = false".to_string());
}
if let Some(extra) = &opts.query {
q_parts.push(extra.clone());
}
let q = if q_parts.is_empty() {
None
} else {
Some(q_parts.join(" and "))
};
let mut params: Vec<(&str, String)> = vec![("fields", DEFAULT_FIELDS.to_string())];
if let Some(q) = q {
params.push(("q", q));
}
if let Some(size) = opts.page_size {
params.push(("pageSize", size.to_string()));
}
if let Some(token) = &opts.page_token {
params.push(("pageToken", token.clone()));
}
if let Some(order) = &opts.order_by {
params.push(("orderBy", order.clone()));
}
let resp = client
.get(FILES_ENDPOINT)
.bearer_auth(access_token)
.query(¶ms)
.send()
.await?;
let status = resp.status().as_u16();
if !resp.status().is_success() {
let msg = resp.text().await.unwrap_or_default();
return Err(DriveError::Api {
status,
message: msg,
});
}
let list: FileList = resp.json().await?;
Ok(list)
}
pub async fn list_all_files(
client: &Client,
access_token: &str,
opts: &ListOptions,
) -> Result<Vec<DriveFile>, DriveError> {
let mut all_files: Vec<DriveFile> = Vec::new();
let mut page_token: Option<String> = opts.page_token.clone();
loop {
let page_opts = ListOptions {
parent_id: opts.parent_id.clone(),
query: opts.query.clone(),
page_size: opts.page_size,
page_token: page_token.clone(),
include_trashed: opts.include_trashed,
order_by: opts.order_by.clone(),
};
let page = list_files(client, access_token, &page_opts).await?;
all_files.extend(page.files);
match page.next_page_token {
Some(token) => page_token = Some(token),
None => break,
}
}
Ok(all_files)
}
pub async fn get_file(
client: &Client,
access_token: &str,
file_id: &str,
) -> Result<DriveFile, DriveError> {
let url = format!("{}/{}", FILES_ENDPOINT, file_id);
let fields = "id,name,mimeType,size,createdTime,modifiedTime,parents,shared,webViewLink,owners,permissions,trashed";
let resp = client
.get(&url)
.bearer_auth(access_token)
.query(&[("fields", fields)])
.send()
.await?;
let status = resp.status().as_u16();
if !resp.status().is_success() {
let msg = resp.text().await.unwrap_or_default();
return Err(DriveError::Api {
status,
message: msg,
});
}
let file: DriveFile = resp.json().await?;
Ok(file)
}
pub async fn delete_file(
client: &Client,
access_token: &str,
file_id: &str,
) -> Result<(), DriveError> {
let url = format!("{}/{}", FILES_ENDPOINT, file_id);
let resp = client
.delete(&url)
.bearer_auth(access_token)
.send()
.await?;
let status = resp.status().as_u16();
if !resp.status().is_success() {
let msg = resp.text().await.unwrap_or_default();
return Err(DriveError::Api {
status,
message: msg,
});
}
Ok(())
}