diff --git a/src/endpoints/adding_tags.rs b/src/endpoints/adding_tags.rs index 15357b8..0a4c338 100644 --- a/src/endpoints/adding_tags.rs +++ b/src/endpoints/adding_tags.rs @@ -42,7 +42,7 @@ pub struct AddTagsRequestBuilder { } /// List of actions for a given tag -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)] pub enum TagAction { /// Add to a local tag service. AddToLocalService, @@ -63,6 +63,8 @@ pub enum TagAction { RescindPetitionFromRepository, } +impl Eq for TagAction {} + impl TagAction { fn into_id(self) -> u8 { match self { diff --git a/src/models/builders/mod.rs b/src/models/builders/mod.rs index 8645e63..2402223 100644 --- a/src/models/builders/mod.rs +++ b/src/models/builders/mod.rs @@ -1 +1,2 @@ pub mod import_builder; +pub mod tagging_builder; diff --git a/src/models/builders/tagging_builder.rs b/src/models/builders/tagging_builder.rs new file mode 100644 index 0000000..435d44c --- /dev/null +++ b/src/models/builders/tagging_builder.rs @@ -0,0 +1,70 @@ +use crate::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction}; +use crate::error::Result; +use crate::models::tag::Tag; +use crate::service::ServiceName; +use crate::Client; +use std::collections::HashMap; + +pub struct TaggingBuilder { + client: Client, + hashes: Vec, + tag_mappings: HashMap>>, +} + +impl TaggingBuilder { + pub(crate) fn new(client: Client) -> Self { + Self { + client, + hashes: Vec::new(), + tag_mappings: Default::default(), + } + } + + /// Adds a file that should get the tags defined for this request + pub fn add_file(mut self, hash: S) -> Self { + self.hashes.push(hash.to_string()); + + self + } + + /// Adds a single tag for a given service + pub fn add_tag(self, service: ServiceName, action: TagAction, tag: Tag) -> Self { + self.add_tags(service, action, vec![tag]) + } + + /// Adds tags with actions for the given service + pub fn add_tags(mut self, service: ServiceName, action: TagAction, mut tags: Vec) -> Self { + let service_action_mappings = + if let Some(service_action_mappings) = self.tag_mappings.get_mut(&service) { + service_action_mappings + } else { + self.tag_mappings.insert(service.clone(), HashMap::new()); + self.tag_mappings.get_mut(&service).unwrap() + }; + if let Some(action_tag_mappings) = service_action_mappings.get_mut(&action) { + action_tag_mappings.append(&mut tags) + } else { + service_action_mappings.insert(action, tags); + } + + self + } + + /// Executes the request + pub async fn run(self) -> Result<()> { + let mut request = AddTagsRequestBuilder::default().add_hashes(self.hashes); + for (service, action_tag_mappings) in self.tag_mappings { + for (action, tags) in action_tag_mappings { + for tag in tags { + request = request.add_tag_with_action( + service.0.clone(), + tag.to_string(), + action.clone(), + ); + } + } + } + + self.client.add_tags(request.build()).await + } +} diff --git a/src/models/hydrus.rs b/src/models/hydrus.rs index 038c136..004d5ea 100644 --- a/src/models/hydrus.rs +++ b/src/models/hydrus.rs @@ -1,4 +1,5 @@ use crate::builders::import_builder::ImportBuilder; +use crate::builders::tagging_builder::TaggingBuilder; use crate::endpoints::common::FileIdentifier; use crate::endpoints::searching_and_fetching_files::FileSearchLocation; use crate::error::Result; @@ -68,6 +69,11 @@ impl Hydrus { Ok(HydrusFile::from_metadata(self.client.clone(), metadata)) } + /// Starts a request to bulk add tags to files + pub fn tagging(&self) -> TaggingBuilder { + TaggingBuilder::new(self.client.clone()) + } + /// Searches for files that have the given tags and returns a list of hydrus files as a result pub async fn search( &self, diff --git a/tests/wrapper/test_hydrus.rs b/tests/wrapper/test_hydrus.rs index 7ce11c9..b919b87 100644 --- a/tests/wrapper/test_hydrus.rs +++ b/tests/wrapper/test_hydrus.rs @@ -1,6 +1,7 @@ use super::super::common; +use hydrus_api::endpoints::adding_tags::TagAction; use hydrus_api::endpoints::searching_and_fetching_files::FileSearchLocation; -use hydrus_api::service::ServiceType; +use hydrus_api::service::{ServiceName, ServiceType}; use hydrus_api::url::UrlType; #[tokio::test] @@ -43,3 +44,19 @@ async fn it_searches() { .await .unwrap(); } + +#[tokio::test] +async fn it_adds_tags() { + let hydrus = common::get_hydrus(); + hydrus + .tagging() + .add_tag( + ServiceName::my_tags(), + TagAction::AddToLocalService, + "summer".into(), + ) + .add_file("0000000000000000000000000000000000000000000000000000000000000000") + .run() + .await + .unwrap(); +}