use crate::{FilesClient, PaginationInfo, Result};
use serde::{Deserialize, Serialize};
use serde_json::json;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BundlePermission {
Read,
Write,
ReadWrite,
Full,
None,
PreviewOnly,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BundleEntity {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub password_protected: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub permissions: Option<BundlePermission>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preview_only: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub require_registration: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub require_share_recipient: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub require_logout: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub clickwrap_body: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub clickwrap_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub skip_name: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub skip_email: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub skip_company: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expires_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_access_on_date: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dont_separate_submissions_by_folder: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_uses: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path_template: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub path_template_time_zone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub send_email_receipt_to_uploader: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub snapshot_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub username: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inbox_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_inbox: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dont_allow_folders_in_uploads: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub paths: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color_left: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color_link: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color_text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color_top: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color_top_text: Option<String>,
}
pub struct BundleHandler {
client: FilesClient,
}
impl BundleHandler {
pub fn new(client: FilesClient) -> Self {
Self { client }
}
pub async fn list(
&self,
user_id: Option<i64>,
cursor: Option<&str>,
per_page: Option<i64>,
) -> Result<(Vec<BundleEntity>, PaginationInfo)> {
let mut params = vec![];
if let Some(uid) = user_id {
params.push(("user_id", uid.to_string()));
}
if let Some(c) = cursor {
params.push(("cursor", c.to_string()));
}
if let Some(pp) = per_page {
params.push(("per_page", pp.to_string()));
}
let query = if params.is_empty() {
String::new()
} else {
format!(
"?{}",
params
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join("&")
)
};
let response = self.client.get_raw(&format!("/bundles{}", query)).await?;
let bundles: Vec<BundleEntity> = serde_json::from_value(response)?;
let pagination = PaginationInfo {
cursor_next: None,
cursor_prev: None,
};
Ok((bundles, pagination))
}
pub async fn get(&self, id: i64) -> Result<BundleEntity> {
let response = self.client.get_raw(&format!("/bundles/{}", id)).await?;
Ok(serde_json::from_value(response)?)
}
#[allow(clippy::too_many_arguments)]
pub async fn create(
&self,
paths: Vec<String>,
password: Option<&str>,
expires_at: Option<&str>,
max_uses: Option<i64>,
description: Option<&str>,
note: Option<&str>,
code: Option<&str>,
require_registration: Option<bool>,
permissions: Option<BundlePermission>,
) -> Result<BundleEntity> {
let mut body = json!({
"paths": paths,
});
if let Some(p) = password {
body["password"] = json!(p);
}
if let Some(e) = expires_at {
body["expires_at"] = json!(e);
}
if let Some(m) = max_uses {
body["max_uses"] = json!(m);
}
if let Some(d) = description {
body["description"] = json!(d);
}
if let Some(n) = note {
body["note"] = json!(n);
}
if let Some(c) = code {
body["code"] = json!(c);
}
if let Some(r) = require_registration {
body["require_registration"] = json!(r);
}
if let Some(perm) = permissions {
body["permissions"] = json!(perm);
}
let response = self.client.post_raw("/bundles", body).await?;
Ok(serde_json::from_value(response)?)
}
#[allow(clippy::too_many_arguments)]
pub async fn update(
&self,
id: i64,
password: Option<&str>,
expires_at: Option<&str>,
max_uses: Option<i64>,
description: Option<&str>,
note: Option<&str>,
) -> Result<BundleEntity> {
let mut body = json!({});
if let Some(p) = password {
body["password"] = json!(p);
}
if let Some(e) = expires_at {
body["expires_at"] = json!(e);
}
if let Some(m) = max_uses {
body["max_uses"] = json!(m);
}
if let Some(d) = description {
body["description"] = json!(d);
}
if let Some(n) = note {
body["note"] = json!(n);
}
let response = self
.client
.patch_raw(&format!("/bundles/{}", id), body)
.await?;
Ok(serde_json::from_value(response)?)
}
pub async fn delete(&self, id: i64) -> Result<()> {
self.client.delete_raw(&format!("/bundles/{}", id)).await?;
Ok(())
}
pub async fn share(&self, id: i64, to: Vec<String>, note: Option<&str>) -> Result<()> {
let mut body = json!({
"to": to,
});
if let Some(n) = note {
body["note"] = json!(n);
}
self.client
.post_raw(&format!("/bundles/{}/share", id), body)
.await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_handler_creation() {
let client = FilesClient::builder().api_key("test-key").build().unwrap();
let _handler = BundleHandler::new(client);
}
}