Add tag cleaning and adding functionality

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/2/head
trivernis 3 years ago
parent 968156aa7d
commit 47b1202056
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -14,6 +14,7 @@ log = "0.4.14"
[dev-dependencies]
env_logger = "0.8.4"
maplit = "1.0.2"
lazy_static = "1.4.0"
[dev-dependencies.tokio]

@ -7,7 +7,9 @@ use crate::paths::adding_files::{
DeleteFilesResponse, UnarchiveFilesRequest, UnarchiveFilesResponse, UndeleteFilesRequest,
UndeleteFilesResponse,
};
use crate::paths::adding_tags::{AddTagsRequest, AddTagsResponse, CleanTagsResponse};
use crate::paths::Path;
use crate::utils::string_list_to_json_array;
use reqwest::Response;
use serde::de::DeserializeOwned;
use serde::Serialize;
@ -165,4 +167,18 @@ impl Client {
Ok(())
}
/// Returns the list of tags as the client would see them in a human friendly order
pub async fn clean_tags(&mut self, tags: Vec<String>) -> Result<CleanTagsResponse> {
self.get_and_parse(&[("tags", string_list_to_json_array(tags))])
.await
}
/// Adds tags to files with the given hashes
pub async fn add_tags(&mut self, request: AddTagsRequest) -> Result<()> {
self.post::<AddTagsResponse, AddTagsRequest>(request)
.await?;
Ok(())
}
}

@ -1,6 +1,7 @@
#[macro_use]
extern crate serde_derive;
pub mod paths;
pub mod client;
mod error;
pub mod paths;
pub(crate) mod utils;

@ -0,0 +1,153 @@
use crate::paths::Path;
use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize)]
pub struct CleanTagsResponse {
pub tags: Vec<String>,
}
impl Path for CleanTagsResponse {
fn get_path() -> String {
String::from("add_tags/clean_tags")
}
}
#[derive(Debug, Clone, Serialize)]
pub struct AddTagsRequest {
pub hashes: Vec<String>,
pub service_names_to_tags: HashMap<String, Vec<String>>,
pub service_names_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>,
}
pub struct AddTagsResponse;
impl Path for AddTagsResponse {
fn get_path() -> String {
String::from("add_tags/add_tags")
}
}
pub struct AddTagsRequestBuilder {
hashes: Vec<String>,
service_names_to_tags: HashMap<String, Vec<String>>,
service_names_to_actions_to_tags: HashMap<String, HashMap<String, Vec<String>>>,
}
/// List of actions for a given tag
pub enum TagAction {
/// Add to a local tag service.
AddToLocalService,
/// Delete from a local tag service.
DeleteFromLocalService,
/// Pend to a tag repository.
PendAddToRepository,
/// Rescind a pend from a tag repository.
RescindPendFromRepository,
/// Petition from a tag repository. (This is special)
PetitionFromRepository,
/// Rescind a petition from a tag repository.
RescindPetitionFromRepository,
}
impl TagAction {
fn into_id(self) -> u8 {
match self {
TagAction::AddToLocalService => 0,
TagAction::DeleteFromLocalService => 1,
TagAction::PendAddToRepository => 2,
TagAction::RescindPendFromRepository => 3,
TagAction::PetitionFromRepository => 4,
TagAction::RescindPetitionFromRepository => 5,
}
}
}
impl Default for AddTagsRequestBuilder {
fn default() -> Self {
Self {
hashes: vec![],
service_names_to_tags: Default::default(),
service_names_to_actions_to_tags: Default::default(),
}
}
}
impl AddTagsRequestBuilder {
/// Adds a file hash to the request
pub fn add_hash<S: AsRef<str>>(mut self, hash: S) -> Self {
self.hashes.push(hash.as_ref().into());
self
}
/// Adds multiple file hashes to the request
pub fn add_hashes(mut self, mut hashes: Vec<String>) -> Self {
self.hashes.append(&mut hashes);
self
}
/// Adds a single tag for a given service
pub fn add_tag<S1: AsRef<str>, S2: AsRef<str>>(mut self, service_name: S1, tag: S2) -> Self {
if let Some(mappings) = self.service_names_to_tags.get_mut(service_name.as_ref()) {
mappings.push(tag.as_ref().into())
} else {
self.service_names_to_tags
.insert(service_name.as_ref().into(), vec![tag.as_ref().into()]);
}
self
}
/// Adds multiple tags for a given service
pub fn add_tags<S1: AsRef<str>>(mut self, service_name: S1, mut tags: Vec<String>) -> Self {
if let Some(mappings) = self.service_names_to_tags.get_mut(service_name.as_ref()) {
mappings.append(&mut tags);
} else {
self.service_names_to_tags
.insert(service_name.as_ref().into(), tags);
}
self
}
/// Adds one tag for a given service with a defined action
pub fn add_tag_with_action<S1: AsRef<str>, S2: AsRef<str>>(
mut self,
service_name: S1,
tag: S2,
action: TagAction,
) -> Self {
let action_id = action.into_id();
if let Some(actions) = self
.service_names_to_actions_to_tags
.get_mut(service_name.as_ref())
{
if let Some(tags) = actions.get_mut(&action_id.to_string()) {
tags.push(tag.as_ref().into());
} else {
actions.insert(action_id.to_string(), vec![tag.as_ref().into()]);
}
} else {
let mut actions = HashMap::new();
actions.insert(action_id.to_string(), vec![tag.as_ref().into()]);
self.service_names_to_actions_to_tags
.insert(service_name.as_ref().into(), actions);
}
self
}
/// builds the request
pub fn build(self) -> AddTagsRequest {
AddTagsRequest {
hashes: self.hashes,
service_names_to_tags: self.service_names_to_tags,
service_names_to_actions_to_tags: self.service_names_to_actions_to_tags,
}
}
}

@ -1,5 +1,6 @@
pub mod access_management;
pub mod adding_files;
pub mod adding_tags;
pub mod common;
pub trait Path {

@ -0,0 +1,3 @@
pub fn string_list_to_json_array(l: Vec<String>) -> String {
format!("[\"{}\"]", l.join("\",\""))
}

@ -0,0 +1,29 @@
use hydrus_api::paths::adding_tags::{AddTagsRequestBuilder, TagAction};
mod common;
#[tokio::test]
async fn it_cleans_tags() {
let mut client = common::get_client();
let response = client
.clean_tags(vec![
"summer".into(),
"rain".into(),
"beach".into(),
"safe".into(),
])
.await
.unwrap();
assert!(response.tags.len() > 0)
}
#[tokio::test]
async fn it_adds_tags() {
let mut client = common::get_client();
let request = AddTagsRequestBuilder::default()
.add_hash("0000000000000000000000000000000000000000000000000000000000000000") // valid hash, I hope no files are affected
.add_tags("my tags", vec!["beach".into(), "summer".into()])
.add_tag_with_action("my tags", "rain", TagAction::DeleteFromLocalService)
.build();
client.add_tags(request).await.unwrap();
}
Loading…
Cancel
Save