use crate::{
queries, utils,
v1::{
bool_from_int, bool_to_int, bool_to_string, optional_bool_from_int, optional_bool_to_int, response_payload,
Deserializer, FileStorageInfo, HasFileMetadata, HasFiles, HasFolders, HasLocationName, HasUuid, LocationColor,
LocationExistsRequestPayload, LocationExistsResponsePayload, LocationKind, LocationNameMetadata,
LocationTrashRequestPayload, PlainResponsePayload, Serializer,
},
FilenSettings,
};
use secstr::SecUtf8;
use serde::{de, Deserialize, Serialize};
use serde_with::skip_serializing_none;
use snafu::{Backtrace, ResultExt, Snafu};
use std::{fmt, str::FromStr};
use uuid::Uuid;
type Result<T, E = Error> = std::result::Result<T, E>;
pub const FILEN_SYNC_FOLDER_NAME: &str = "Filen Sync";
const USER_BASE_FOLDERS_PATH: &str = "/v1/user/baseFolders";
const USER_DIRS_PATH: &str = "/v1/user/dirs";
const DIR_CONTENT_PATH: &str = "/v1/dir/content";
const DIR_CREATE_PATH: &str = "/v1/dir/create";
const DIR_SUB_CREATE_PATH: &str = "/v1/dir/sub/create";
const DIR_EXISTS_PATH: &str = "/v1/dir/exists";
const DIR_MOVE_PATH: &str = "/v1/dir/move";
const DIR_RENAME_PATH: &str = "/v1/dir/rename";
const DIR_RESTORE_PATH: &str = "/v1/dir/restore";
const DIR_TRASH_PATH: &str = "/v1/dir/trash";
#[derive(Snafu, Debug)]
pub enum Error {
#[snafu(display("Caller provided invalid argument: {}", message))]
BadArgument { message: String, backtrace: Backtrace },
#[snafu(display(
"Expected \"trash\" or hyphenated lowercased UUID, got unknown string of length: {}",
string_length
))]
CannotParseContentKindFromString { string_length: usize, backtrace: Backtrace },
#[snafu(display("{} query failed: {}", USER_BASE_FOLDERS_PATH, source))]
UserBaseFoldersQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", USER_DIRS_PATH, source))]
UserDirsQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_CONTENT_PATH, source))]
DirContentQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_CREATE_PATH, source))]
DirCreateQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_SUB_CREATE_PATH, source))]
DirSubCreateQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_EXISTS_PATH, source))]
DirExistsQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_MOVE_PATH, source))]
DirMoveQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_RENAME_PATH, source))]
DirRenameQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_RESTORE_PATH, source))]
DirRestoreQueryFailed { source: queries::Error },
#[snafu(display("{} query failed: {}", DIR_TRASH_PATH, source))]
DirTrashQueryFailed { source: queries::Error },
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum ContentKind {
Trash,
Folder(Uuid),
}
impl FromStr for ContentKind {
type Err = Error;
fn from_str(trash_or_id: &str) -> Result<Self, Self::Err> {
if trash_or_id.eq_ignore_ascii_case("trash") {
Ok(Self::Trash)
} else {
match Uuid::parse_str(trash_or_id) {
Ok(uuid) => Ok(Self::Folder(uuid)),
Err(_) => CannotParseContentKindFromStringSnafu {
string_length: trash_or_id.len(),
}
.fail(),
}
}
}
}
impl fmt::Display for ContentKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ContentKind::Trash => write!(f, "trash"),
ContentKind::Folder(uuid) => uuid.as_hyphenated().fmt(f),
}
}
}
impl<'de> Deserialize<'de> for ContentKind {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let trash_or_id = String::deserialize(deserializer)?;
if trash_or_id.eq_ignore_ascii_case("trash") {
Ok(Self::Trash)
} else {
match Uuid::parse_str(&trash_or_id) {
Ok(uuid) => Ok(Self::Folder(uuid)),
Err(_) => Err(de::Error::invalid_value(
de::Unexpected::Str(&trash_or_id),
&"\"trash\" or hyphenated lowercased UUID",
)),
}
}
}
}
impl Serialize for ContentKind {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
ContentKind::Trash => serializer.serialize_str("trash"),
ContentKind::Folder(uuid) => serializer.serialize_str(&uuid.as_hyphenated().to_string()),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct UserBaseFoldersRequestPayload<'user_base_folders> {
#[serde(rename = "apiKey")]
pub api_key: &'user_base_folders SecUtf8,
#[serde(rename = "includeDefault", serialize_with = "bool_to_string")]
pub include_default: bool,
}
utils::display_from_json_with_lifetime!('user_base_folders, UserBaseFoldersRequestPayload);
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct UserBaseFolder {
pub uuid: Uuid,
#[serde(rename = "name")]
pub name_metadata: String,
pub color: Option<LocationColor>,
pub timestamp: u64,
#[serde(deserialize_with = "bool_from_int", serialize_with = "bool_to_int")]
pub favorited: bool,
#[serde(deserialize_with = "bool_from_int", serialize_with = "bool_to_int")]
pub is_default: bool,
#[serde(deserialize_with = "bool_from_int", serialize_with = "bool_to_int")]
pub is_sync: bool,
}
utils::display_from_json!(UserBaseFolder);
impl HasLocationName for UserBaseFolder {
fn name_metadata_ref(&self) -> &str {
&self.name_metadata
}
}
impl HasUuid for UserBaseFolder {
fn uuid_ref(&self) -> &Uuid {
&self.uuid
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct UserBaseFoldersResponseData {
pub folders: Vec<UserBaseFolder>,
}
utils::display_from_json!(UserBaseFoldersResponseData);
response_payload!(
UserBaseFoldersResponsePayload<UserBaseFoldersResponseData>
);
impl HasFolders<UserBaseFolder> for UserBaseFoldersResponseData {
fn folders_ref(&self) -> &[UserBaseFolder] {
&self.folders
}
}
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct UserDirData {
pub uuid: Uuid,
#[serde(rename = "name")]
pub name_metadata: String,
pub parent: Option<Uuid>,
pub default: bool,
pub sync: bool,
pub is_default: u32,
pub is_sync: u32,
pub color: Option<LocationColor>,
}
utils::display_from_json!(UserDirData);
impl HasLocationName for UserDirData {
fn name_metadata_ref(&self) -> &str {
&self.name_metadata
}
}
impl HasUuid for UserDirData {
fn uuid_ref(&self) -> &Uuid {
&self.uuid
}
}
response_payload!(
UserDirsResponsePayload<Vec<UserDirData>>
);
impl UserDirsResponsePayload {
#[must_use]
pub fn find_default_folder(&self) -> Option<UserDirData> {
self.data
.as_ref()
.and_then(|data| data.iter().find(|dir_data| dir_data.default).cloned())
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DirContentRequestPayload<'dir_content> {
#[serde(rename = "apiKey")]
pub api_key: &'dir_content SecUtf8,
pub uuid: ContentKind,
pub folders: String,
pub page: i32,
#[serde(serialize_with = "bool_to_string")]
pub app: bool,
}
utils::display_from_json_with_lifetime!('dir_content, DirContentRequestPayload);
impl<'dir_content> DirContentRequestPayload<'dir_content> {
#[must_use]
pub fn new(api_key: &'dir_content SecUtf8, folder_uuid: ContentKind) -> Self {
let folders = format!("[\"{}\"]", folder_uuid);
Self {
api_key,
uuid: folder_uuid,
folders,
page: 1,
app: true,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct DirContentFile {
pub uuid: Uuid,
pub metadata: String,
pub rm: String,
#[serde(flatten)]
pub storage: FileStorageInfo,
#[serde(
rename = "expireSet",
deserialize_with = "bool_from_int",
serialize_with = "bool_to_int"
)]
pub expire_set: bool,
#[serde(rename = "expireTimestamp")]
pub expire_timestamp: u64,
#[serde(rename = "deleteTimestamp")]
pub delete_timestamp: u64,
pub timestamp: u64,
#[serde(rename = "trashTimestamp")]
pub trash_timestamp: Option<u64>,
pub parent: Uuid,
pub version: u32,
#[serde(deserialize_with = "bool_from_int", serialize_with = "bool_to_int")]
pub favorited: bool,
}
utils::display_from_json!(DirContentFile);
impl HasFileMetadata for DirContentFile {
fn file_metadata_ref(&self) -> &str {
&self.metadata
}
}
impl HasUuid for DirContentFile {
fn uuid_ref(&self) -> &Uuid {
&self.uuid
}
}
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct DirContentFolder {
pub uuid: Uuid,
#[serde(rename = "name")]
pub name_metadata: String,
pub parent: Option<Uuid>,
pub color: Option<LocationColor>,
pub timestamp: u64,
#[serde(deserialize_with = "bool_from_int", serialize_with = "bool_to_int")]
pub favorited: bool,
#[serde(default)]
#[serde(deserialize_with = "optional_bool_from_int", serialize_with = "optional_bool_to_int")]
pub is_default: Option<bool>,
#[serde(default)]
#[serde(deserialize_with = "optional_bool_from_int", serialize_with = "optional_bool_to_int")]
pub is_sync: Option<bool>,
#[serde(default)]
#[serde(deserialize_with = "optional_bool_from_int", serialize_with = "optional_bool_to_int")]
pub trash_parent: Option<bool>,
pub trash_timestamp: Option<u64>,
}
utils::display_from_json!(DirContentFolder);
impl HasLocationName for DirContentFolder {
fn name_metadata_ref(&self) -> &str {
self.name_metadata.as_ref()
}
}
impl HasUuid for DirContentFolder {
fn uuid_ref(&self) -> &Uuid {
&self.uuid
}
}
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct DirContentFolderInfo {
pub uuid: ContentKind,
#[serde(rename = "name")]
pub name_metadata: String,
pub color: Option<LocationColor>,
}
utils::display_from_json!(DirContentFolderInfo);
#[skip_serializing_none]
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct DirContentResponseData {
pub uploads: Vec<DirContentFile>,
pub folders: Vec<DirContentFolder>,
#[serde(rename = "foldersInfo")]
pub folders_info: Vec<DirContentFolderInfo>,
#[serde(rename = "totalUploads")]
pub total_uploads: u64,
#[serde(rename = "startAt")]
pub start_at: u32,
#[serde(rename = "perPage")]
pub per_page: u32,
pub page: u32,
}
utils::display_from_json!(DirContentResponseData);
impl HasFiles<DirContentFile> for DirContentResponseData {
fn files_ref(&self) -> &[DirContentFile] {
&self.uploads
}
}
impl HasFolders<DirContentFolder> for DirContentResponseData {
fn folders_ref(&self) -> &[DirContentFolder] {
&self.folders
}
}
response_payload!(
DirContentResponsePayload<DirContentResponseData>
);
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DirCreateRequestPayload<'dir_create> {
#[serde(rename = "apiKey")]
pub api_key: &'dir_create SecUtf8,
#[serde(rename = "name")]
pub name_metadata: String,
#[serde(rename = "nameHashed")]
pub name_hashed: String,
#[serde(rename = "type")]
pub dir_type: LocationKind,
pub uuid: Uuid,
}
utils::display_from_json_with_lifetime!('dir_create, DirCreateRequestPayload);
impl<'dir_create> DirCreateRequestPayload<'dir_create> {
#[must_use]
pub fn payload_for_sync_folder_creation(api_key: &'dir_create SecUtf8, last_master_key: &SecUtf8) -> Self {
let mut payload = Self::new(api_key, FILEN_SYNC_FOLDER_NAME, last_master_key);
payload.dir_type = LocationKind::Sync;
payload
}
#[must_use]
pub fn new(api_key: &'dir_create SecUtf8, name: &str, last_master_key: &SecUtf8) -> Self {
let name_metadata = LocationNameMetadata::encrypt_name_to_metadata(name, last_master_key);
let name_hashed = LocationNameMetadata::name_hashed(name);
Self {
api_key,
uuid: Uuid::new_v4(),
name_metadata,
name_hashed,
dir_type: LocationKind::Folder,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DirSubCreateRequestPayload<'dir_sub_create> {
#[serde(rename = "apiKey")]
pub api_key: &'dir_sub_create SecUtf8,
#[serde(rename = "name")]
pub name_metadata: String,
#[serde(rename = "nameHashed")]
pub name_hashed: String,
pub parent: Uuid,
pub uuid: Uuid,
}
utils::display_from_json_with_lifetime!('dir_sub_create, DirSubCreateRequestPayload);
impl<'dir_sub_create> DirSubCreateRequestPayload<'dir_sub_create> {
#[must_use]
pub fn new(api_key: &'dir_sub_create SecUtf8, name: &str, parent: Uuid, last_master_key: &SecUtf8) -> Self {
let name_metadata = LocationNameMetadata::encrypt_name_to_metadata(name, last_master_key);
let name_hashed = LocationNameMetadata::name_hashed(name);
Self {
api_key,
uuid: Uuid::new_v4(),
name_metadata,
name_hashed,
parent,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DirMoveRequestPayload<'dir_move> {
#[serde(rename = "apiKey")]
pub api_key: &'dir_move SecUtf8,
#[serde(rename = "folderUUID")]
pub folder_uuid: Uuid,
pub uuid: Uuid,
}
utils::display_from_json_with_lifetime!('dir_move, DirMoveRequestPayload);
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DirRenameRequestPayload<'dir_rename> {
#[serde(rename = "apiKey")]
pub api_key: &'dir_rename SecUtf8,
pub uuid: Uuid,
#[serde(rename = "name")]
pub name_metadata: String,
#[serde(rename = "nameHashed")]
pub name_hashed: String,
}
utils::display_from_json_with_lifetime!('dir_rename, DirRenameRequestPayload);
impl<'dir_rename> DirRenameRequestPayload<'dir_rename> {
#[must_use]
pub fn new(
api_key: &'dir_rename SecUtf8,
folder_uuid: Uuid,
new_folder_name: &str,
last_master_key: &SecUtf8,
) -> Self {
let name_metadata = LocationNameMetadata::encrypt_name_to_metadata(new_folder_name, last_master_key);
let name_hashed = LocationNameMetadata::name_hashed(new_folder_name);
Self {
api_key,
uuid: folder_uuid,
name_metadata,
name_hashed,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DirRestoreRequestPayload<'dir_restore> {
#[serde(rename = "apiKey")]
pub api_key: &'dir_restore SecUtf8,
pub uuid: Uuid,
}
utils::display_from_json_with_lifetime!('dir_restore, DirRestoreRequestPayload);
pub fn user_base_folders_request(
payload: &UserBaseFoldersRequestPayload,
filen_settings: &FilenSettings,
) -> Result<UserBaseFoldersResponsePayload> {
queries::query_filen_api(USER_BASE_FOLDERS_PATH, payload, filen_settings)
.context(UserBaseFoldersQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn user_base_folders_request_async(
payload: &UserBaseFoldersRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<UserBaseFoldersResponsePayload> {
queries::query_filen_api_async(USER_BASE_FOLDERS_PATH, payload, filen_settings)
.await
.context(UserBaseFoldersQueryFailedSnafu {})
}
pub fn user_dirs_request(api_key: &SecUtf8, filen_settings: &FilenSettings) -> Result<UserDirsResponsePayload> {
queries::query_filen_api(USER_DIRS_PATH, &utils::api_key_json(api_key), filen_settings)
.context(UserDirsQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn user_dirs_request_async(
api_key: &SecUtf8,
filen_settings: &FilenSettings,
) -> Result<UserDirsResponsePayload> {
queries::query_filen_api_async(USER_DIRS_PATH, &utils::api_key_json(api_key), filen_settings)
.await
.context(UserDirsQueryFailedSnafu {})
}
pub fn dir_content_request(
payload: &DirContentRequestPayload,
filen_settings: &FilenSettings,
) -> Result<DirContentResponsePayload> {
queries::query_filen_api(DIR_CONTENT_PATH, payload, filen_settings).context(DirContentQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_content_request_async(
payload: &DirContentRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<DirContentResponsePayload> {
queries::query_filen_api_async(DIR_CONTENT_PATH, payload, filen_settings)
.await
.context(DirContentQueryFailedSnafu {})
}
pub fn dir_create_request(
payload: &DirCreateRequestPayload,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api(DIR_CREATE_PATH, payload, filen_settings).context(DirCreateQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_create_request_async(
payload: &DirCreateRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api_async(DIR_CREATE_PATH, payload, filen_settings)
.await
.context(DirCreateQueryFailedSnafu {})
}
pub fn dir_sub_create_request(
payload: &DirSubCreateRequestPayload,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api(DIR_SUB_CREATE_PATH, payload, filen_settings).context(DirSubCreateQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_sub_create_request_async(
payload: &DirSubCreateRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api_async(DIR_SUB_CREATE_PATH, payload, filen_settings)
.await
.context(DirSubCreateQueryFailedSnafu {})
}
pub fn dir_exists_request(
payload: &LocationExistsRequestPayload,
filen_settings: &FilenSettings,
) -> Result<LocationExistsResponsePayload> {
queries::query_filen_api(DIR_EXISTS_PATH, payload, filen_settings).context(DirExistsQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_exists_request_async(
payload: &LocationExistsRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<LocationExistsResponsePayload> {
queries::query_filen_api_async(DIR_EXISTS_PATH, payload, filen_settings)
.await
.context(DirExistsQueryFailedSnafu {})
}
pub fn dir_move_request(
payload: &DirMoveRequestPayload,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api(DIR_MOVE_PATH, payload, filen_settings).context(DirMoveQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_move_request_async(
payload: &DirMoveRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api_async(DIR_MOVE_PATH, payload, filen_settings)
.await
.context(DirMoveQueryFailedSnafu {})
}
pub fn dir_rename_request(
payload: &DirRenameRequestPayload,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api(DIR_RENAME_PATH, payload, filen_settings).context(DirRenameQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_rename_request_async(
payload: &DirRenameRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api_async(DIR_RENAME_PATH, payload, filen_settings)
.await
.context(DirRenameQueryFailedSnafu {})
}
pub fn dir_restore_request(
payload: &DirRestoreRequestPayload,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api(DIR_RESTORE_PATH, payload, filen_settings).context(DirRestoreQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_restore_request_async(
payload: &DirRestoreRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api_async(DIR_RESTORE_PATH, payload, filen_settings)
.await
.context(DirRestoreQueryFailedSnafu {})
}
pub fn dir_trash_request(
payload: &LocationTrashRequestPayload,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api(DIR_TRASH_PATH, payload, filen_settings).context(DirTrashQueryFailedSnafu {})
}
#[cfg(feature = "async")]
pub async fn dir_trash_request_async(
payload: &LocationTrashRequestPayload<'_>,
filen_settings: &FilenSettings,
) -> Result<PlainResponsePayload> {
queries::query_filen_api_async(DIR_TRASH_PATH, payload, filen_settings)
.await
.context(DirTrashQueryFailedSnafu {})
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "async")]
use crate::test_utils::validate_contract_async;
use crate::{test_utils::validate_contract, v1::ParentOrBase};
use once_cell::sync::Lazy;
use pretty_assertions::assert_eq;
use secstr::SecUtf8;
static API_KEY: Lazy<SecUtf8> =
Lazy::new(|| SecUtf8::from("bYZmrwdVEbHJSqeA1RfnPtKiBcXzUpRdKGRkjw9m1o1eqSGP1s6DM11CDnklpFq6"));
const NAME: &str = "test_folder";
const NAME_METADATA: &str = "U2FsdGVkX19d09wR+Ti+qMO7o8habxXkS501US7uv96+zbHHZwDDPbnq1di1z0/S";
const NAME_HASHED: &str = "19d24c63b1170a0b1b40520a636a25235735f39f";
#[test]
fn content_kind_should_be_deserialized_from_trash() {
let json = r#""trash""#;
let expected = ContentKind::Trash;
let result = serde_json::from_str::<ContentKind>(json);
assert_eq!(result.unwrap(), expected);
}
#[test]
fn content_kind_should_be_deserialized_from_id() {
let json = r#""00000000-0000-0000-0000-000000000000""#;
let expected = ContentKind::Folder(Uuid::nil());
let result = serde_json::from_str::<ContentKind>(json);
assert_eq!(result.unwrap(), expected);
}
#[test]
fn dir_create_request_payload_should_be_created_correctly_from_name() {
let m_key = SecUtf8::from("b49cadfb92e1d7d54e9dd9d33ba9feb2af1f10ae");
let payload = DirCreateRequestPayload::new(&API_KEY, NAME, &m_key);
let decrypted_name =
LocationNameMetadata::decrypt_name_from_metadata(&payload.name_metadata, &[m_key]).unwrap();
assert_eq!(payload.api_key, &*API_KEY);
assert_eq!(decrypted_name, NAME);
assert_eq!(payload.name_hashed, NAME_HASHED);
assert_eq!(payload.dir_type, LocationKind::Folder);
}
#[test]
fn user_dirs_request_should_have_proper_contract() {
let request_payload = utils::api_key_json(&API_KEY);
validate_contract(
USER_DIRS_PATH,
request_payload,
"tests/resources/responses/user_dirs_default.json",
|_, filen_settings| user_dirs_request(&API_KEY, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn user_dirs_request_async_should_have_proper_contract() {
let request_payload = utils::api_key_json(&API_KEY);
validate_contract_async(
USER_DIRS_PATH,
request_payload,
"tests/resources/responses/user_dirs_default.json",
|_, filen_settings| async move { user_dirs_request_async(&API_KEY, &filen_settings).await },
)
.await;
}
#[test]
fn dir_content_request_should_have_proper_contract() {
let request_payload = DirContentRequestPayload {
api_key: &API_KEY,
uuid: ContentKind::Folder(Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap()),
folders: "[\"51845ac9-47ce-4820-aedb-876f591aef84\"]".to_owned(),
page: 1,
app: true,
};
validate_contract(
DIR_CONTENT_PATH,
request_payload,
"tests/resources/responses/dir_content.json",
|request_payload, filen_settings| dir_content_request(&request_payload, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn dir_content_request_async_should_have_proper_contract() {
let request_payload = DirContentRequestPayload {
api_key: &API_KEY,
uuid: ContentKind::Folder(Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap()),
folders: "[\"51845ac9-47ce-4820-aedb-876f591aef84\"]".to_owned(),
page: 1,
app: true,
};
validate_contract_async(
DIR_CONTENT_PATH,
request_payload,
"tests/resources/responses/dir_content.json",
|request_payload, filen_settings| async move {
dir_content_request_async(&request_payload, &filen_settings).await
},
)
.await;
}
#[test]
fn dir_content_request_should_have_proper_contract_for_trash() {
let request_payload = DirContentRequestPayload {
api_key: &API_KEY,
uuid: ContentKind::Trash,
folders: "[\"51845ac9-47ce-4820-aedb-876f591aef84\"]".to_owned(),
page: 1,
app: true,
};
validate_contract(
DIR_CONTENT_PATH,
request_payload,
"tests/resources/responses/dir_content_trash.json",
|request_payload, filen_settings| dir_content_request(&request_payload, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn dir_content_request_async_should_have_proper_contract_for_trash() {
let request_payload = DirContentRequestPayload {
api_key: &API_KEY,
uuid: ContentKind::Trash,
folders: "[\"51845ac9-47ce-4820-aedb-876f591aef84\"]".to_owned(),
page: 1,
app: true,
};
validate_contract_async(
DIR_CONTENT_PATH,
request_payload,
"tests/resources/responses/dir_content_trash.json",
|request_payload, filen_settings| async move {
dir_content_request_async(&request_payload, &filen_settings).await
},
)
.await;
}
#[test]
fn dir_create_request_should_have_proper_contract() {
let request_payload = DirCreateRequestPayload {
api_key: &API_KEY,
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_metadata: NAME_METADATA.to_owned(),
name_hashed: NAME_HASHED.to_owned(),
dir_type: LocationKind::Folder,
};
validate_contract(
DIR_CREATE_PATH,
request_payload,
"tests/resources/responses/dir_create.json",
|request_payload, filen_settings| dir_create_request(&request_payload, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn dir_create_request_async_should_have_proper_contract() {
let request_payload = DirCreateRequestPayload {
api_key: &API_KEY,
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_metadata: NAME_METADATA.to_owned(),
name_hashed: NAME_HASHED.to_owned(),
dir_type: LocationKind::Folder,
};
validate_contract_async(
DIR_CREATE_PATH,
request_payload,
"tests/resources/responses/dir_create.json",
|request_payload, filen_settings| async move {
dir_create_request_async(&request_payload, &filen_settings).await
},
)
.await;
}
#[test]
fn dir_sub_create_request_should_have_proper_contract() {
let request_payload = DirSubCreateRequestPayload {
api_key: &API_KEY,
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_metadata: NAME_METADATA.to_owned(),
name_hashed: NAME_HASHED.to_owned(),
parent: Uuid::parse_str("14fab199-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
};
validate_contract(
DIR_SUB_CREATE_PATH,
request_payload,
"tests/resources/responses/dir_sub_create.json",
|request_payload, filen_settings| dir_sub_create_request(&request_payload, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn dir_sub_create_request_async_should_have_proper_contract() {
let request_payload = DirSubCreateRequestPayload {
api_key: &API_KEY,
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_metadata: NAME_METADATA.to_owned(),
name_hashed: NAME_HASHED.to_owned(),
parent: Uuid::parse_str("14fab199-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
};
validate_contract_async(
DIR_SUB_CREATE_PATH,
request_payload,
"tests/resources/responses/dir_sub_create.json",
|request_payload, filen_settings| async move {
dir_sub_create_request_async(&request_payload, &filen_settings).await
},
)
.await;
}
#[test]
fn dir_exists_request_should_have_proper_contract() {
let request_payload = LocationExistsRequestPayload {
api_key: &API_KEY,
parent: ParentOrBase::from_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_hashed: NAME_HASHED.to_owned(),
};
validate_contract(
DIR_EXISTS_PATH,
request_payload,
"tests/resources/responses/dir_exists.json",
|request_payload, filen_settings| dir_exists_request(&request_payload, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn dir_exists_request_async_should_have_proper_contract() {
let request_payload = LocationExistsRequestPayload {
api_key: &API_KEY,
parent: ParentOrBase::from_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_hashed: NAME_HASHED.to_owned(),
};
validate_contract_async(
DIR_EXISTS_PATH,
request_payload,
"tests/resources/responses/dir_exists.json",
|request_payload, filen_settings| async move {
dir_exists_request_async(&request_payload, &filen_settings).await
},
)
.await;
}
#[test]
fn dir_move_request_should_have_proper_contract() {
let request_payload = DirMoveRequestPayload {
api_key: &API_KEY,
folder_uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
};
validate_contract(
DIR_MOVE_PATH,
request_payload,
"tests/resources/responses/dir_move.json",
|request_payload, filen_settings| dir_move_request(&request_payload, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn dir_move_request_async_should_have_proper_contract() {
let request_payload = DirMoveRequestPayload {
api_key: &API_KEY,
folder_uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
};
validate_contract_async(
DIR_MOVE_PATH,
request_payload,
"tests/resources/responses/dir_move.json",
|request_payload, filen_settings| async move { dir_move_request_async(&request_payload, &filen_settings).await },
).await;
}
#[test]
fn dir_rename_request_should_have_proper_contract() {
let request_payload = DirRenameRequestPayload {
api_key: &API_KEY,
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_metadata: NAME_METADATA.to_owned(),
name_hashed: NAME_HASHED.to_owned(),
};
validate_contract(
DIR_RENAME_PATH,
request_payload,
"tests/resources/responses/dir_rename.json",
|request_payload, filen_settings| dir_rename_request(&request_payload, &filen_settings),
);
}
#[cfg(feature = "async")]
#[tokio::test]
async fn dir_rename_request_async_should_have_proper_contract() {
let request_payload = DirRenameRequestPayload {
api_key: &API_KEY,
uuid: Uuid::parse_str("80f678c0-56ce-4b81-b4ef-f2a9c0c737c4").unwrap(),
name_metadata: NAME_METADATA.to_owned(),
name_hashed: NAME_HASHED.to_owned(),
};
validate_contract_async(
DIR_RENAME_PATH,
request_payload,
"tests/resources/responses/dir_rename.json",
|request_payload, filen_settings| async move {
dir_rename_request_async(&request_payload, &filen_settings).await
},
)
.await;
}
}