Add service selection to undelete, archive and unarchive

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/15/head
trivernis 3 years ago
parent 0e8c28c948
commit 6b06a9cf60
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -1,4 +1,7 @@
use crate::api_core::common::{FileIdentifier, FileMetadataInfo, FileRecord, OptionalStringNumber}; use crate::api_core::common::{
FileIdentifier, FileMetadataInfo, FileRecord, FileSelection, FileServiceSelection,
OptionalStringNumber,
};
use crate::api_core::endpoints::access_management::{ use crate::api_core::endpoints::access_management::{
ApiVersion, ApiVersionResponse, GetServices, GetServicesResponse, SessionKey, ApiVersion, ApiVersionResponse, GetServices, GetServicesResponse, SessionKey,
SessionKeyResponse, VerifyAccessKey, VerifyAccessKeyResponse, SessionKeyResponse, VerifyAccessKey, VerifyAccessKeyResponse,
@ -110,35 +113,66 @@ impl Client {
/// Moves files with matching hashes to the trash /// Moves files with matching hashes to the trash
#[tracing::instrument(skip(self), level = "debug")] #[tracing::instrument(skip(self), level = "debug")]
pub async fn delete_files(&self, request: DeleteFilesRequest) -> Result<()> { pub async fn delete_files(
self.post::<DeleteFiles>(request).await?; &self,
files: FileSelection,
service: FileServiceSelection,
reason: Option<String>,
) -> Result<()> {
self.post::<DeleteFiles>(DeleteFilesRequest {
file_selection: files,
service_selection: service,
reason,
})
.await?;
Ok(()) Ok(())
} }
/// Pulls files out of the trash by hash /// Pulls files out of the trash by hash
#[tracing::instrument(skip(self), level = "debug")] #[tracing::instrument(skip(self), level = "debug")]
pub async fn undelete_files(&self, hashes: Vec<String>) -> Result<()> { pub async fn undelete_files(
self.post::<UndeleteFiles>(UndeleteFilesRequest { hashes }) &self,
.await?; files: FileSelection,
service: FileServiceSelection,
) -> Result<()> {
self.post::<UndeleteFiles>(UndeleteFilesRequest {
file_selection: files,
service_selection: service,
})
.await?;
Ok(()) Ok(())
} }
/// Moves files from the inbox into the archive /// Moves files from the inbox into the archive
#[tracing::instrument(skip(self), level = "debug")] #[tracing::instrument(skip(self), level = "debug")]
pub async fn archive_files(&self, hashes: Vec<String>) -> Result<()> { pub async fn archive_files(
self.post::<ArchiveFiles>(ArchiveFilesRequest { hashes }) &self,
.await?; files: FileSelection,
service: FileServiceSelection,
) -> Result<()> {
self.post::<ArchiveFiles>(ArchiveFilesRequest {
file_selection: files,
service_selection: service,
})
.await?;
Ok(()) Ok(())
} }
/// Moves files from the archive into the inbox /// Moves files from the archive into the inbox
#[tracing::instrument(skip(self), level = "debug")] #[tracing::instrument(skip(self), level = "debug")]
pub async fn unarchive_files(&self, hashes: Vec<String>) -> Result<()> { pub async fn unarchive_files(
self.post::<UnarchiveFiles>(UnarchiveFilesRequest { hashes }) &self,
.await?; files: FileSelection,
service: FileServiceSelection,
) -> Result<()> {
self.post::<UnarchiveFiles>(UnarchiveFilesRequest {
file_selection: files,
service_selection: service,
})
.await?;
Ok(()) Ok(())
} }

@ -1,3 +1,5 @@
use crate::wrapper::service::ServiceName;
use serde::Serialize;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -98,6 +100,119 @@ impl FileIdentifier {
} }
} }
/// A generic selection for one or multiple files
#[derive(Clone, Debug, Serialize, Default)]
pub struct FileSelection {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) hash: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub(crate) hashes: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) file_id: Option<u64>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub(crate) file_ids: Vec<u64>,
}
impl From<FileIdentifier> for FileSelection {
fn from(id: FileIdentifier) -> Self {
let mut selection = Self::default();
match id {
FileIdentifier::ID(id) => selection.file_id = Some(id),
FileIdentifier::Hash(hash) => selection.hash = Some(hash),
}
selection
}
}
impl FileSelection {
/// Creates a new single hash file selection
pub fn by_hash<S: ToString>(hash: S) -> Self {
Self {
hash: Some(hash.to_string()),
..Default::default()
}
}
/// Creates a new file selection with a single file id
pub fn by_file_id(file_id: u64) -> Self {
Self {
file_id: Some(file_id),
..Default::default()
}
}
/// Creates a new file selection with several hashes
pub fn by_hashes(mut hashes: Vec<String>) -> Self {
if hashes.len() == 1 {
Self::by_hash(hashes.pop().unwrap())
} else {
Self {
hashes,
..Default::default()
}
}
}
/// Creates a new file selection with several IDs
pub fn by_file_ids(mut file_ids: Vec<u64>) -> Self {
if file_ids.len() == 1 {
Self::by_file_id(file_ids.pop().unwrap())
} else {
Self {
file_ids,
..Default::default()
}
}
}
}
/// A selection for a single file service
#[derive(Clone, Debug, Serialize, Default)]
pub struct FileServiceSelection {
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) file_service_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) file_service_key: Option<String>,
}
impl FileServiceSelection {
/// Creates a new file service selection by name
pub fn by_name<S: ToString>(name: S) -> Self {
Self {
file_service_name: Some(name.to_string()),
..Default::default()
}
}
/// Creates a new file service selection by service key
pub fn by_key<S: ToString>(key: S) -> Self {
Self {
file_service_key: Some(key.to_string()),
..Default::default()
}
}
/// Selects no service
pub fn none() -> Self {
Self::default()
}
}
impl From<ServiceIdentifier> for FileServiceSelection {
fn from(id: ServiceIdentifier) -> Self {
match id {
ServiceIdentifier::Name(n) => Self::by_name(n),
ServiceIdentifier::Key(k) => Self::by_key(k),
}
}
}
impl From<ServiceName> for FileServiceSelection {
fn from(name: ServiceName) -> Self {
Self::by_name(name)
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct FileRecord { pub struct FileRecord {
pub bytes: Vec<u8>, pub bytes: Vec<u8>,

@ -1,4 +1,4 @@
use crate::api_core::common::{BasicHashList, ServiceIdentifier}; use crate::api_core::common::{FileSelection, FileServiceSelection};
use crate::api_core::endpoints::Endpoint; use crate::api_core::endpoints::Endpoint;
use serde::Serialize; use serde::Serialize;
@ -33,41 +33,13 @@ impl Endpoint for AddFile {
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
pub struct DeleteFilesRequest { pub struct DeleteFilesRequest {
/// The files by hashes to delete #[serde(flatten)]
pub hashes: Vec<String>, pub file_selection: FileSelection,
/// The files by file ids to delete #[serde(flatten)]
pub file_ids: Vec<u64>, pub service_selection: FileServiceSelection,
pub file_service_name: Option<String>,
pub file_service_key: Option<String>,
pub reason: Option<String>, pub reason: Option<String>,
} }
impl DeleteFilesRequest {
pub fn new(hashes: Vec<String>, file_ids: Vec<u64>) -> Self {
Self {
hashes,
file_ids,
file_service_key: None,
file_service_name: None,
reason: None,
}
}
/// Sets the service to delete from. If none is given it deletes
/// from all files.
pub fn set_service(&mut self, service: ServiceIdentifier) {
match service {
ServiceIdentifier::Name(name) => self.file_service_name = Some(name),
ServiceIdentifier::Key(key) => self.file_service_key = Some(key),
}
}
/// Sets the reason for deletion
pub fn set_reason<S: ToString>(&mut self, reason: S) {
self.reason = Some(reason.to_string());
}
}
pub struct DeleteFiles; pub struct DeleteFiles;
impl Endpoint for DeleteFiles { impl Endpoint for DeleteFiles {
@ -79,7 +51,14 @@ impl Endpoint for DeleteFiles {
} }
} }
pub type UndeleteFilesRequest = BasicHashList; #[derive(Clone, Debug, Serialize)]
pub struct UndeleteFilesRequest {
#[serde(flatten)]
pub file_selection: FileSelection,
#[serde(flatten)]
pub service_selection: FileServiceSelection,
}
pub struct UndeleteFiles; pub struct UndeleteFiles;
impl Endpoint for UndeleteFiles { impl Endpoint for UndeleteFiles {
@ -91,7 +70,14 @@ impl Endpoint for UndeleteFiles {
} }
} }
pub type ArchiveFilesRequest = BasicHashList; #[derive(Clone, Debug, Serialize)]
pub struct ArchiveFilesRequest {
#[serde(flatten)]
pub file_selection: FileSelection,
#[serde(flatten)]
pub service_selection: FileServiceSelection,
}
pub struct ArchiveFiles; pub struct ArchiveFiles;
impl Endpoint for ArchiveFiles { impl Endpoint for ArchiveFiles {
@ -103,11 +89,18 @@ impl Endpoint for ArchiveFiles {
} }
} }
pub type UnarchiveFilesRequest = BasicHashList; #[derive(Clone, Debug, Serialize)]
pub struct UnarchiveFilesRequest {
#[serde(flatten)]
pub file_selection: FileSelection,
#[serde(flatten)]
pub service_selection: FileServiceSelection,
}
pub struct UnarchiveFiles; pub struct UnarchiveFiles;
impl Endpoint for UnarchiveFiles { impl Endpoint for UnarchiveFiles {
type Request = UndeleteFilesRequest; type Request = UnarchiveFilesRequest;
type Response = (); type Response = ();
fn path() -> String { fn path() -> String {

@ -1,5 +1,6 @@
use crate::api_core::common::{FileIdentifier, ServiceIdentifier}; use crate::api_core::common::{
use crate::api_core::endpoints::adding_files::DeleteFilesRequest; FileIdentifier, FileSelection, FileServiceSelection, ServiceIdentifier,
};
use crate::error::Result; use crate::error::Result;
use crate::Client; use crate::Client;
@ -53,20 +54,18 @@ impl DeleteFilesBuilder {
/// Deletes all files specified in this builder /// Deletes all files specified in this builder
pub async fn run(self) -> Result<()> { pub async fn run(self) -> Result<()> {
let mut request = DeleteFilesRequest { let file_selection = FileSelection {
reason: self.reason,
hashes: self.hashes, hashes: self.hashes,
file_ids: self.ids, file_ids: self.ids,
file_service_key: None, ..Default::default()
file_service_name: None,
}; };
if let Some(service) = self.service { let service_selection = self
match service { .service
ServiceIdentifier::Name(name) => request.file_service_name = Some(name), .map(FileServiceSelection::from)
ServiceIdentifier::Key(key) => request.file_service_key = Some(key), .unwrap_or_default();
}
}
self.client.delete_files(request).await self.client
.delete_files(file_selection, service_selection, self.reason)
.await
} }
} }

@ -1,4 +1,7 @@
use crate::api_core::common::{FileIdentifier, FileMetadataInfo, FileRecord, ServiceIdentifier}; use crate::api_core::common::{
FileIdentifier, FileMetadataInfo, FileRecord, FileSelection, FileServiceSelection,
ServiceIdentifier,
};
use crate::api_core::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction}; use crate::api_core::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction};
use crate::error::{Error, Result}; use crate::error::{Error, Result};
use crate::utils::tag_list_to_string_list; use crate::utils::tag_list_to_string_list;
@ -240,7 +243,9 @@ impl HydrusFile {
pub async fn undelete(&mut self) -> Result<()> { pub async fn undelete(&mut self) -> Result<()> {
let hash = self.hash().await?; let hash = self.hash().await?;
self.metadata = None; self.metadata = None;
self.client.undelete_files(vec![hash]).await self.client
.undelete_files(FileSelection::by_hash(hash), FileServiceSelection::none())
.await
} }
/// Associates the file with a list of urls /// Associates the file with a list of urls

@ -1,7 +1,7 @@
use crate::common; use crate::common;
use crate::common::create_testdata; use crate::common::create_testdata;
use crate::common::test_data::get_test_hashes; use crate::common::test_data::{get_test_hashes, TEST_HASH_1};
use hydrus_api::api_core::endpoints::adding_files::DeleteFilesRequest; use hydrus_api::api_core::common::FileSelection;
use hydrus_api::wrapper::service::ServiceName; use hydrus_api::wrapper::service::ServiceName;
#[tokio::test] #[tokio::test]
@ -25,29 +25,51 @@ async fn it_adds_binary_files() {
async fn it_deletes_files() { async fn it_deletes_files() {
let client = common::get_client(); let client = common::get_client();
create_testdata(&client).await; create_testdata(&client).await;
let mut delete_request = DeleteFilesRequest::new(get_test_hashes(), vec![]); client
delete_request.set_reason("Testing"); .delete_files(
delete_request.set_service(ServiceName::my_files().into()); FileSelection::by_hashes(get_test_hashes()),
client.delete_files(delete_request).await.unwrap(); ServiceName::my_files().into(),
Some("Test".to_string()),
)
.await
.unwrap();
} }
#[tokio::test] #[tokio::test]
async fn it_undeletes_files() { async fn it_undeletes_files() {
let client = common::get_client(); let client = common::get_client();
create_testdata(&client).await; create_testdata(&client).await;
client.undelete_files(get_test_hashes()).await.unwrap(); client
.undelete_files(
FileSelection::by_hashes(get_test_hashes()),
ServiceName::my_files().into(),
)
.await
.unwrap();
} }
#[tokio::test] #[tokio::test]
async fn it_archives_files() { async fn it_archives_files() {
let client = common::get_client(); let client = common::get_client();
create_testdata(&client).await; create_testdata(&client).await;
client.archive_files(get_test_hashes()).await.unwrap(); client
.archive_files(
FileSelection::by_hashes(vec![TEST_HASH_1.to_string()]),
ServiceName::my_files().into(),
)
.await
.unwrap();
} }
#[tokio::test] #[tokio::test]
async fn it_unarchives_files() { async fn it_unarchives_files() {
let client = common::get_client(); let client = common::get_client();
create_testdata(&client).await; create_testdata(&client).await;
client.unarchive_files(get_test_hashes()).await.unwrap(); client
.unarchive_files(
FileSelection::by_hashes(get_test_hashes()),
ServiceName::my_files().into(),
)
.await
.unwrap();
} }

Loading…
Cancel
Save