Add functions to files to retrieve information, associate urls and get tags

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 3 years ago
parent 188da6c4c1
commit 7d6b2bfe96
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -11,7 +11,7 @@ use crate::endpoints::adding_urls::{
AddUrl, AddUrlRequest, AddUrlResponse, AssociateUrl, AssociateUrlRequest, GetUrlFiles,
GetUrlFilesResponse, GetUrlInfo, GetUrlInfoResponse,
};
use crate::endpoints::common::{FileIdentifier, FileRecord};
use crate::endpoints::common::{FileIdentifier, FileMetadataInfo, FileRecord};
use crate::endpoints::searching_and_fetching_files::{
FileMetadata, FileMetadataResponse, FileSearchLocation, GetFile, SearchFiles,
SearchFilesResponse,
@ -43,10 +43,10 @@ impl Client {
}
/// Starts a get request to the path
async fn get<E: Endpoint, Q: Serialize + ?Sized>(&mut self, query: &Q) -> Result<Response> {
async fn get<E: Endpoint, Q: Serialize + ?Sized>(&self, query: &Q) -> Result<Response> {
let response = self
.inner
.get(format!("{}/{}", self.base_url, E::get_path()))
.get(format!("{}/{}", self.base_url, E::path()))
.header(ACCESS_KEY_HEADER, &self.access_key)
.query(query)
.send()
@ -57,7 +57,7 @@ impl Client {
/// Starts a get request to the path associated with the Endpoint Type
async fn get_and_parse<E: Endpoint, Q: Serialize + ?Sized>(
&mut self,
&self,
query: &Q,
) -> Result<E::Response> {
let response = self.get::<E, Q>(query).await?;
@ -66,10 +66,10 @@ impl Client {
}
/// Stats a post request to the path associated with the Endpoint Type
async fn post<E: Endpoint>(&mut self, body: E::Request) -> Result<Response> {
async fn post<E: Endpoint>(&self, body: E::Request) -> Result<Response> {
let response = self
.inner
.post(format!("{}/{}", self.base_url, E::get_path()))
.post(format!("{}/{}", self.base_url, E::path()))
.json(&body)
.header(ACCESS_KEY_HEADER, &self.access_key)
.send()
@ -79,17 +79,17 @@ impl Client {
}
/// Stats a post request and parses the body as json
async fn post_and_parse<E: Endpoint>(&mut self, body: E::Request) -> Result<E::Response> {
async fn post_and_parse<E: Endpoint>(&self, body: E::Request) -> Result<E::Response> {
let response = self.post::<E>(body).await?;
Self::extract_content(response).await
}
/// Stats a post request to the path associated with the return type
async fn post_binary<E: Endpoint>(&mut self, data: Vec<u8>) -> Result<E::Response> {
async fn post_binary<E: Endpoint>(&self, data: Vec<u8>) -> Result<E::Response> {
let response = self
.inner
.post(format!("{}/{}", self.base_url, E::get_path()))
.post(format!("{}/{}", self.base_url, E::path()))
.body(data)
.header(ACCESS_KEY_HEADER, &self.access_key)
.header("Content-Type", "application/octet-stream")
@ -116,27 +116,27 @@ impl Client {
}
/// Returns the current API version. It's being incremented every time the API changes.
pub async fn api_version(&mut self) -> Result<ApiVersionResponse> {
pub async fn api_version(&self) -> Result<ApiVersionResponse> {
self.get_and_parse::<ApiVersion, ()>(&()).await
}
/// Creates a new session key
pub async fn session_key(&mut self) -> Result<SessionKeyResponse> {
pub async fn session_key(&self) -> Result<SessionKeyResponse> {
self.get_and_parse::<SessionKey, ()>(&()).await
}
/// Verifies if the access key is valid and returns some information about its permissions
pub async fn verify_access_key(&mut self) -> Result<VerifyAccessKeyResponse> {
pub async fn verify_access_key(&self) -> Result<VerifyAccessKeyResponse> {
self.get_and_parse::<VerifyAccessKey, ()>(&()).await
}
/// Returns the list of tag and file services of the client
pub async fn get_services(&mut self) -> Result<GetServicesResponse> {
pub async fn get_services(&self) -> Result<GetServicesResponse> {
self.get_and_parse::<GetServices, ()>(&()).await
}
/// Adds a file to hydrus
pub async fn add_file<S: AsRef<str>>(&mut self, path: S) -> Result<AddFileResponse> {
pub async fn add_file<S: AsRef<str>>(&self, path: S) -> Result<AddFileResponse> {
self.post_and_parse::<AddFile>(AddFileRequest {
path: path.as_ref().to_string(),
})
@ -144,12 +144,12 @@ impl Client {
}
/// Adds a file from binary data to hydrus
pub async fn add_binary_file(&mut self, data: Vec<u8>) -> Result<AddFileResponse> {
pub async fn add_binary_file(&self, data: Vec<u8>) -> Result<AddFileResponse> {
self.post_binary::<AddFile>(data).await
}
/// Moves files with matching hashes to the trash
pub async fn delete_files(&mut self, hashes: Vec<String>) -> Result<()> {
pub async fn delete_files(&self, hashes: Vec<String>) -> Result<()> {
self.post::<DeleteFiles>(DeleteFilesRequest { hashes })
.await?;
@ -157,7 +157,7 @@ impl Client {
}
/// Pulls files out of the trash by hash
pub async fn undelete_files(&mut self, hashes: Vec<String>) -> Result<()> {
pub async fn undelete_files(&self, hashes: Vec<String>) -> Result<()> {
self.post::<UndeleteFiles>(UndeleteFilesRequest { hashes })
.await?;
@ -165,7 +165,7 @@ impl Client {
}
/// Moves files from the inbox into the archive
pub async fn archive_files(&mut self, hashes: Vec<String>) -> Result<()> {
pub async fn archive_files(&self, hashes: Vec<String>) -> Result<()> {
self.post::<ArchiveFiles>(ArchiveFilesRequest { hashes })
.await?;
@ -173,7 +173,7 @@ impl Client {
}
/// Moves files from the archive into the inbox
pub async fn unarchive_files(&mut self, hashes: Vec<String>) -> Result<()> {
pub async fn unarchive_files(&self, hashes: Vec<String>) -> Result<()> {
self.post::<UnarchiveFiles>(UnarchiveFilesRequest { hashes })
.await?;
@ -181,7 +181,7 @@ impl Client {
}
/// 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> {
pub async fn clean_tags(&self, tags: Vec<String>) -> Result<CleanTagsResponse> {
self.get_and_parse::<CleanTags, [(&str, String)]>(&[(
"tags",
string_list_to_json_array(tags),
@ -190,7 +190,7 @@ impl Client {
}
/// Adds tags to files with the given hashes
pub async fn add_tags(&mut self, request: AddTagsRequest) -> Result<()> {
pub async fn add_tags(&self, request: AddTagsRequest) -> Result<()> {
self.post::<AddTags>(request).await?;
Ok(())
@ -198,7 +198,7 @@ impl Client {
/// Searches for files in the inbox, the archive or both
pub async fn search_files(
&mut self,
&self,
tags: Vec<String>,
location: FileSearchLocation,
) -> Result<SearchFilesResponse> {
@ -212,19 +212,37 @@ impl Client {
/// Returns the metadata for a given list of file_ids or hashes
pub async fn get_file_metadata(
&mut self,
&self,
file_ids: Vec<u64>,
hashes: Vec<String>,
) -> Result<FileMetadataResponse> {
self.get_and_parse::<FileMetadata, [(&str, String)]>(&[
("file_ids", number_list_to_json_array(file_ids)),
("hashes", string_list_to_json_array(hashes)),
])
.await
let query = if file_ids.len() > 0 {
("file_ids", number_list_to_json_array(file_ids))
} else {
("hashes", string_list_to_json_array(hashes))
};
self.get_and_parse::<FileMetadata, [(&str, String)]>(&[query])
.await
}
/// Returns the metadata for a single file identifier
pub async fn get_file_metadata_by_identifier(
&self,
identifier: FileIdentifier,
) -> Result<FileMetadataInfo> {
let mut response = match identifier.clone() {
FileIdentifier::ID(id) => self.get_file_metadata(vec![id], vec![]).await?,
FileIdentifier::Hash(hash) => self.get_file_metadata(vec![], vec![hash]).await?,
};
response
.metadata
.pop()
.ok_or_else(|| Error::FileNotFound(identifier))
}
/// Returns the bytes of a file from hydrus
pub async fn get_file(&mut self, id: FileIdentifier) -> Result<FileRecord> {
pub async fn get_file(&self, id: FileIdentifier) -> Result<FileRecord> {
let response = match id {
FileIdentifier::ID(id) => {
self.get::<GetFile, [(&str, u64)]>(&[("file_id", id)])
@ -248,24 +266,24 @@ impl Client {
}
/// Returns all files associated with the given url
pub async fn get_url_files<S: AsRef<str>>(&mut self, url: S) -> Result<GetUrlFilesResponse> {
pub async fn get_url_files<S: AsRef<str>>(&self, url: S) -> Result<GetUrlFilesResponse> {
self.get_and_parse::<GetUrlFiles, [(&str, &str)]>(&[("url", url.as_ref())])
.await
}
/// Returns information about the given url
pub async fn get_url_info<S: AsRef<str>>(&mut self, url: S) -> Result<GetUrlInfoResponse> {
pub async fn get_url_info<S: AsRef<str>>(&self, url: S) -> Result<GetUrlInfoResponse> {
self.get_and_parse::<GetUrlInfo, [(&str, &str)]>(&[("url", url.as_ref())])
.await
}
/// Adds an url to hydrus, optionally with additional tags and a destination page
pub async fn add_url(&mut self, request: AddUrlRequest) -> Result<AddUrlResponse> {
pub async fn add_url(&self, request: AddUrlRequest) -> Result<AddUrlResponse> {
self.post_and_parse::<AddUrl>(request).await
}
/// Associates urls with the given file hashes
pub async fn associate_urls(&mut self, urls: Vec<String>, hashes: Vec<String>) -> Result<()> {
pub async fn associate_urls(&self, urls: Vec<String>, hashes: Vec<String>) -> Result<()> {
self.post::<AssociateUrl>(AssociateUrlRequest {
hashes,
urls_to_add: urls,
@ -277,11 +295,7 @@ impl Client {
}
/// Disassociates urls with the given file hashes
pub async fn disassociate_urls(
&mut self,
urls: Vec<String>,
hashes: Vec<String>,
) -> Result<()> {
pub async fn disassociate_urls(&self, urls: Vec<String>, hashes: Vec<String>) -> Result<()> {
self.post::<AssociateUrl>(AssociateUrlRequest {
hashes,
urls_to_add: vec![],

@ -23,7 +23,7 @@ impl Endpoint for ApiVersion {
type Request = ();
type Response = ApiVersionResponse;
fn get_path() -> String {
fn path() -> String {
String::from("api_version")
}
}
@ -39,7 +39,7 @@ impl Endpoint for SessionKey {
type Request = ();
type Response = SessionKeyResponse;
fn get_path() -> String {
fn path() -> String {
String::from("session_key")
}
}
@ -56,7 +56,7 @@ impl Endpoint for VerifyAccessKey {
type Request = ();
type Response = VerifyAccessKeyResponse;
fn get_path() -> String {
fn path() -> String {
String::from("verify_access_key")
}
}
@ -70,7 +70,7 @@ impl Endpoint for GetServices {
type Request = ();
type Response = GetServicesResponse;
fn get_path() -> String {
fn path() -> String {
String::from("get_services")
}
}

@ -25,7 +25,7 @@ impl Endpoint for AddFile {
type Request = AddFileRequest;
type Response = AddFileResponse;
fn get_path() -> String {
fn path() -> String {
String::from("add_files/add_file")
}
}
@ -38,7 +38,7 @@ impl Endpoint for DeleteFiles {
type Request = DeleteFilesRequest;
type Response = ();
fn get_path() -> String {
fn path() -> String {
String::from("add_files/delete_files")
}
}
@ -50,7 +50,7 @@ impl Endpoint for UndeleteFiles {
type Request = UndeleteFilesRequest;
type Response = ();
fn get_path() -> String {
fn path() -> String {
String::from("add_files/undelete_files")
}
}
@ -62,7 +62,7 @@ impl Endpoint for ArchiveFiles {
type Request = ArchiveFilesRequest;
type Response = ();
fn get_path() -> String {
fn path() -> String {
String::from("add_files/archive_files")
}
}
@ -74,7 +74,7 @@ impl Endpoint for UnarchiveFiles {
type Request = UndeleteFilesRequest;
type Response = ();
fn get_path() -> String {
fn path() -> String {
String::from("add_files/unarchive_files")
}
}

@ -12,7 +12,7 @@ impl Endpoint for CleanTags {
type Request = ();
type Response = CleanTagsResponse;
fn get_path() -> String {
fn path() -> String {
String::from("add_tags/clean_tags")
}
}
@ -30,7 +30,7 @@ impl Endpoint for AddTags {
type Request = AddTagsRequest;
type Response = ();
fn get_path() -> String {
fn path() -> String {
String::from("add_tags/add_tags")
}
}

@ -27,7 +27,7 @@ impl Endpoint for GetUrlFiles {
type Request = ();
type Response = GetUrlFilesResponse;
fn get_path() -> String {
fn path() -> String {
String::from("add_urls/get_url_files")
}
}
@ -47,7 +47,7 @@ impl Endpoint for GetUrlInfo {
type Request = ();
type Response = GetUrlInfoResponse;
fn get_path() -> String {
fn path() -> String {
String::from("add_urls/get_url_info")
}
}
@ -164,7 +164,7 @@ impl Endpoint for AddUrl {
type Request = AddUrlRequest;
type Response = AddUrlResponse;
fn get_path() -> String {
fn path() -> String {
String::from("add_urls/add_url")
}
}
@ -181,7 +181,7 @@ impl Endpoint for AssociateUrl {
type Request = AssociateUrlRequest;
type Response = ();
fn get_path() -> String {
fn path() -> String {
String::from("add_urls/associate_url")
}
}

@ -11,17 +11,17 @@ pub struct BasicHashList {
pub hashes: Vec<String>,
}
#[derive(Clone, Default, Deserialize)]
#[derive(Clone, Debug, Default, Deserialize)]
pub struct FileMetadataInfo {
pub file_id: u64,
pub hash: String,
pub size: u64,
pub size: Option<u64>,
pub mime: String,
pub ext: String,
pub width: u32,
pub height: u32,
pub width: Option<u32>,
pub height: Option<u32>,
pub duration: Option<u64>,
pub has_audio: bool,
pub has_audio: Option<bool>,
pub num_frames: Option<u16>,
pub num_words: Option<u64>,
pub is_inbox: bool,
@ -32,12 +32,18 @@ pub struct FileMetadataInfo {
pub service_names_to_statuses_to_display_tags: HashMap<String, HashMap<String, Vec<String>>>,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum FileIdentifier {
ID(u64),
Hash(String),
}
impl FileIdentifier {
pub fn hash<S: ToString>(hash: S) -> Self {
Self::Hash(hash.to_string())
}
}
#[derive(Clone)]
pub struct FileRecord {
pub bytes: Vec<u8>,

@ -8,9 +8,9 @@ pub mod adding_urls;
pub mod common;
pub mod searching_and_fetching_files;
pub trait Endpoint {
pub(crate) trait Endpoint {
type Request: Serialize;
type Response: DeserializeOwned;
fn get_path() -> String;
fn path() -> String;
}

@ -44,14 +44,14 @@ impl Endpoint for SearchFiles {
type Request = ();
type Response = SearchFilesResponse;
fn get_path() -> String {
fn path() -> String {
String::from("get_files/search_files")
}
}
#[derive(Clone, Default, Deserialize)]
#[derive(Clone, Debug, Default, Deserialize)]
pub struct FileMetadataResponse {
metadata: Vec<FileMetadataInfo>,
pub metadata: Vec<FileMetadataInfo>,
}
pub struct FileMetadata;
@ -60,7 +60,7 @@ impl Endpoint for FileMetadata {
type Request = ();
type Response = FileMetadataResponse;
fn get_path() -> String {
fn path() -> String {
String::from("get_files/file_metadata")
}
}
@ -71,7 +71,7 @@ impl Endpoint for GetFile {
type Request = ();
type Response = ();
fn get_path() -> String {
fn path() -> String {
String::from("get_files/file")
}
}

@ -1,3 +1,4 @@
use crate::endpoints::common::FileIdentifier;
use std::error::Error as StdError;
use std::fmt;
@ -10,6 +11,7 @@ pub enum Error {
InvalidServiceType(String),
ImportVetoed(String),
ImportFailed(String),
FileNotFound(FileIdentifier),
}
impl fmt::Display for Error {
@ -22,6 +24,7 @@ impl fmt::Display for Error {
}
Self::ImportFailed(msg) => write!(f, "File import failed: {}", msg),
Self::ImportVetoed(msg) => write!(f, "File import vetoed: {}", msg),
Self::FileNotFound(id) => write!(f, "File {:?} not found", id),
}
}
}
@ -30,10 +33,7 @@ impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Reqwest(e) => e.source(),
Self::Hydrus(_) => None,
Self::InvalidServiceType(_) => None,
Self::ImportVetoed(_) => None,
Self::ImportFailed(_) => None,
_ => None,
}
}
}

@ -51,7 +51,7 @@ pub struct FileImportBuilder {
}
impl FileImportBuilder {
pub async fn run(mut self) -> Result<HydrusFile> {
pub async fn run(self) -> Result<HydrusFile> {
let response = match self.file {
FileImport::Path(path) => self.client.add_file(path).await?,
FileImport::Binary(b) => self.client.add_binary_file(b).await?,
@ -137,7 +137,7 @@ impl UrlImportBuilder {
}
/// Imports the URL
pub async fn run(mut self) -> Result<Url> {
pub async fn run(self) -> Result<Url> {
let mut request = AddUrlRequestBuilder::default().url(&self.url);
for (service, tags) in self.service_tag_mappings {

@ -1,5 +1,7 @@
use crate::builders::import_builder::ImportBuilder;
use crate::endpoints::common::FileIdentifier;
use crate::error::Result;
use crate::hydrus_file::HydrusFile;
use crate::models::url::Url;
use crate::models::version::Version;
use crate::service::Services;
@ -16,7 +18,7 @@ impl Hydrus {
}
/// Returns the Hydrus and API Version
pub async fn version(&mut self) -> Result<Version> {
pub async fn version(&self) -> Result<Version> {
let response = self.client.api_version().await?;
Ok(Version {
api: response.version,
@ -25,14 +27,14 @@ impl Hydrus {
}
/// Returns a list of available services
pub async fn services(&mut self) -> Result<Services> {
pub async fn services(&self) -> Result<Services> {
let response = self.client.get_services().await?;
Ok(Services::from_response(self.client.clone(), response))
}
/// Creates an import builder to build an import request to hydrus
pub fn import(&mut self) -> ImportBuilder {
pub fn import(&self) -> ImportBuilder {
ImportBuilder {
client: self.client.clone(),
}
@ -40,7 +42,7 @@ impl Hydrus {
/// Returns information about a given url in an object that allows
/// further operations with that url
pub async fn url<S: AsRef<str>>(&mut self, url: S) -> Result<Url> {
pub async fn url<S: AsRef<str>>(&self, url: S) -> Result<Url> {
let info = self.client.get_url_info(&url).await?;
Ok(Url {
@ -52,4 +54,14 @@ impl Hydrus {
can_parse: info.can_parse,
})
}
/// Returns a file by identifier to perform further operations on
pub async fn file(&self, identifier: FileIdentifier) -> Result<HydrusFile> {
let metadata = self
.client
.get_file_metadata_by_identifier(identifier)
.await?;
Ok(HydrusFile::from_metadata(self.client.clone(), metadata))
}
}

@ -1,5 +1,9 @@
use crate::endpoints::common::FileIdentifier;
use crate::endpoints::common::{FileIdentifier, FileMetadataInfo};
use crate::error::Result;
use crate::service::ServiceName;
use crate::tag::Tag;
use crate::Client;
use std::collections::HashMap;
#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum FileStatus {
@ -16,6 +20,7 @@ pub struct HydrusFile {
pub(crate) client: Client,
pub id: FileIdentifier,
pub status: FileStatus,
pub(crate) metadata: Option<FileMetadataInfo>,
}
impl HydrusFile {
@ -35,6 +40,101 @@ impl HydrusFile {
client,
id: FileIdentifier::Hash(hash.to_string()),
status,
metadata: None,
}
}
pub(crate) fn from_metadata(client: Client, metadata: FileMetadataInfo) -> Self {
let status = if metadata.is_trashed {
FileStatus::Deleted
} else {
FileStatus::InDatabase
};
Self {
client,
id: FileIdentifier::Hash(metadata.hash.clone()),
status,
metadata: Some(metadata),
}
}
/// Deletes the internally stored metadata about the file retrieves it again
pub async fn update(&mut self) -> Result<()> {
self.metadata = None;
self.metadata().await?;
Ok(())
}
/// Returns the metadata for the given file
/// if there's already known metadata about the file it uses that
async fn metadata(&mut self) -> Result<&FileMetadataInfo> {
if self.metadata.is_none() {
let metadata = self
.client
.get_file_metadata_by_identifier(self.id.clone())
.await?;
self.status = if metadata.is_trashed {
FileStatus::Deleted
} else {
FileStatus::InDatabase
};
self.metadata = Some(metadata);
}
Ok(self.metadata.as_ref().unwrap())
}
/// Returns the hash of the file
/// if the file identifier is an id it calls hydrus to resolve the file
pub async fn hash(&mut self) -> Result<String> {
match &self.id {
FileIdentifier::ID(_) => {
let metadata = self.metadata().await?;
Ok(metadata.hash.clone())
}
FileIdentifier::Hash(hash) => Ok(hash.clone()),
}
}
/// Associates the file with a list of urls
pub async fn associate_urls(&mut self, urls: Vec<String>) -> Result<()> {
let hash = self.hash().await?;
self.client.associate_urls(urls, vec![hash]).await
}
/// Disassociates the file with a list of urls
pub async fn disassociate_urls(&mut self, urls: Vec<String>) -> Result<()> {
let hash = self.hash().await?;
self.client.disassociate_urls(urls, vec![hash]).await
}
/// Returns map mapping lists of tags to services
pub async fn services_with_tags(&mut self) -> Result<HashMap<ServiceName, Vec<Tag>>> {
let metadata = self.metadata().await?;
let mut tag_mappings = HashMap::new();
for (service, status_tags) in &metadata.service_names_to_statuses_to_tags {
let mut tag_list = Vec::new();
for (_, tags) in status_tags {
tag_list.append(&mut tags.into_iter().map(|t| t.into()).collect())
}
tag_mappings.insert(ServiceName(service.clone()), tag_list);
}
Ok(tag_mappings)
}
/// Returns a list of all tags assigned to the file
pub async fn tags(&mut self) -> Result<Vec<Tag>> {
let mut tag_list = Vec::new();
let tag_mappings = self.services_with_tags().await?;
for (_, mut tags) in tag_mappings {
tag_list.append(&mut tags);
}
Ok(tag_list)
}
}

@ -56,9 +56,11 @@ impl ToString for ServiceType {
}
}
#[derive(Clone)]
#[derive(Clone, PartialOrd, PartialEq, Hash)]
pub struct ServiceName(pub String);
impl Eq for ServiceName {}
impl ServiceName {
pub fn my_tags() -> Self {
Self(String::from("my tags"))

@ -2,7 +2,7 @@ use super::super::common;
#[tokio::test]
async fn it_returns_the_api_version() {
let mut client = common::get_client();
let client = common::get_client();
let api_version = client.api_version().await.unwrap();
assert!(api_version.hydrus_version > 0);
assert!(api_version.version > 0);
@ -10,14 +10,14 @@ async fn it_returns_the_api_version() {
#[tokio::test]
async fn it_returns_the_session_key() {
let mut client = common::get_client();
let client = common::get_client();
let session_key = client.session_key().await.unwrap();
assert!(session_key.session_key.len() > 0);
}
#[tokio::test]
async fn it_verifies_the_access_key() {
let mut client = common::get_client();
let client = common::get_client();
let verification_response = client.verify_access_key().await.unwrap();
assert!(verification_response.basic_permissions.len() > 0); // needs to be configured in the client but we want at least some permissions for the test
assert!(verification_response.human_description.len() > 0);
@ -25,7 +25,7 @@ async fn it_verifies_the_access_key() {
#[tokio::test]
async fn it_returns_a_list_of_services() {
let mut client = common::get_client();
let client = common::get_client();
let services_response = client.get_services().await.unwrap();
assert!(services_response.0.keys().len() > 0);
}

@ -2,14 +2,14 @@ use super::super::common;
#[tokio::test]
async fn it_adds_files() {
let mut client = common::get_client();
let client = common::get_client();
let result = client.add_file("/does/not/exist").await;
assert!(result.is_err()); // because the path does not exist
}
#[tokio::test]
async fn it_adds_binary_files() {
let mut client = common::get_client();
let client = common::get_client();
let result = client
.add_binary_file(vec![0u8, 0u8, 0u8, 0u8])
.await
@ -19,24 +19,24 @@ async fn it_adds_binary_files() {
#[tokio::test]
async fn it_deletes_files() {
let mut client = common::get_client();
let client = common::get_client();
client.delete_files(vec![]).await.unwrap();
}
#[tokio::test]
async fn it_undeletes_files() {
let mut client = common::get_client();
let client = common::get_client();
client.undelete_files(vec![]).await.unwrap();
}
#[tokio::test]
async fn it_archives_files() {
let mut client = common::get_client();
let client = common::get_client();
client.archive_files(vec![]).await.unwrap();
}
#[tokio::test]
async fn it_unarchives_files() {
let mut client = common::get_client();
let client = common::get_client();
client.unarchive_files(vec![]).await.unwrap();
}

@ -3,7 +3,7 @@ use hydrus_api::endpoints::adding_tags::{AddTagsRequestBuilder, TagAction};
#[tokio::test]
async fn it_cleans_tags() {
let mut client = common::get_client();
let client = common::get_client();
let response = client
.clean_tags(vec![
"summer".into(),
@ -18,7 +18,7 @@ async fn it_cleans_tags() {
#[tokio::test]
async fn it_adds_tags() {
let mut client = common::get_client();
let 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()])

@ -3,7 +3,7 @@ use hydrus_api::endpoints::adding_urls::{AddUrlRequestBuilder, URL_TYPE_POST};
#[tokio::test]
async fn it_returns_files_for_an_url() {
let mut client = common::get_client();
let client = common::get_client();
let response = client
.get_url_files("https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium")
.await
@ -14,7 +14,7 @@ async fn it_returns_files_for_an_url() {
#[tokio::test]
async fn it_returns_url_information() {
let mut client = common::get_client();
let client = common::get_client();
let info = client
.get_url_info("https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium")
.await
@ -25,7 +25,7 @@ async fn it_returns_url_information() {
#[tokio::test]
async fn it_adds_urls() {
let mut client = common::get_client();
let client = common::get_client();
let request = AddUrlRequestBuilder::default()
.url("https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium")
.add_tags(
@ -41,7 +41,7 @@ async fn it_adds_urls() {
#[tokio::test]
async fn it_associates_urls() {
let mut client = common::get_client();
let client = common::get_client();
client
.associate_urls(
vec![
@ -56,7 +56,7 @@ async fn it_associates_urls() {
#[tokio::test]
async fn it_disassociates_urls() {
let mut client = common::get_client();
let client = common::get_client();
client
.disassociate_urls(
vec![

@ -4,7 +4,7 @@ use hydrus_api::endpoints::searching_and_fetching_files::FileSearchLocation;
#[tokio::test]
async fn is_searches_files() {
let mut client = common::get_client();
let client = common::get_client();
client
.search_files(vec!["beach".to_string()], FileSearchLocation::Archive)
.await
@ -13,19 +13,19 @@ async fn is_searches_files() {
#[tokio::test]
async fn it_fetches_file_metadata() {
let mut client = common::get_client();
client
let client = common::get_client();
let response = client
.get_file_metadata(
vec![],
vec!["0000000000000000000000000000000000000000000000000000000000000000".to_string()],
)
.await
.unwrap();
.await;
assert!(response.is_ok()); // Even if the file doesn't exist it still returns some information about it
}
#[tokio::test]
async fn it_fetches_single_files() {
let mut client = common::get_client();
let client = common::get_client();
let response = client
.get_file(FileIdentifier::Hash(
"0000000000000000000000000000000000000000000000000000000000000000".to_string(),

@ -1,3 +1,4 @@
mod test_files;
mod test_hydrus;
mod test_import;
mod test_url;

@ -0,0 +1,49 @@
use super::super::common;
use hydrus_api::endpoints::common::FileIdentifier;
use hydrus_api::hydrus_file::HydrusFile;
async fn get_file() -> HydrusFile {
let hydrus = common::get_hydrus();
hydrus
.file(FileIdentifier::hash(
"277a138cd1ee79fc1fdb2869c321b848d4861e45b82184487139ef66dd40b62d", // needs to exist
))
.await
.unwrap()
}
#[tokio::test]
async fn it_associates_with_urls() {
let mut file = get_file().await;
file.associate_urls(vec![
"https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium".to_string(),
])
.await
.unwrap();
}
#[tokio::test]
async fn it_disassociates_with_urls() {
let mut file = get_file().await;
file.disassociate_urls(vec![
"https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium".to_string(),
])
.await
.unwrap();
}
#[tokio::test]
async fn it_has_tags_with_services() {
let mut file = get_file().await;
let tags = file.services_with_tags().await.unwrap();
assert!(tags.keys().len() > 0)
}
#[tokio::test]
async fn it_has_tags() {
let mut file = get_file().await;
let tags = file.tags().await.unwrap();
assert!(tags.len() > 0) // test data needs to be prepared this way
}

@ -4,7 +4,7 @@ use hydrus_api::url::UrlType;
#[tokio::test]
async fn it_retrieves_version_info() {
let mut hydrus = common::get_hydrus();
let hydrus = common::get_hydrus();
let version = hydrus.version().await.unwrap();
assert!(version.hydrus > 0);
assert!(version.api > 0);
@ -12,7 +12,7 @@ async fn it_retrieves_version_info() {
#[tokio::test]
async fn it_retrieves_services() {
let mut hydrus = common::get_hydrus();
let hydrus = common::get_hydrus();
let services = hydrus.services().await.unwrap();
// assuming hydrus is configured correctly
@ -22,7 +22,7 @@ async fn it_retrieves_services() {
#[tokio::test]
async fn it_retrieves_url_information() {
let mut hydrus = common::get_hydrus();
let hydrus = common::get_hydrus();
let url = hydrus
.url("https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium")
.await

@ -7,7 +7,7 @@ use hydrus_api::url::UrlType;
#[tokio::test]
async fn it_imports_file_paths() {
let mut hydrus = common::get_hydrus();
let hydrus = common::get_hydrus();
let result = hydrus
.import()
.file(FileImport::path("/does/not/exist/sadly"))
@ -19,7 +19,7 @@ async fn it_imports_file_paths() {
#[tokio::test]
async fn it_imports_binary_files() {
let mut hydrus = common::get_hydrus();
let hydrus = common::get_hydrus();
let bytes = [0u8, 0u8, 0u8, 0u8];
let result = hydrus
.import()
@ -32,7 +32,7 @@ async fn it_imports_binary_files() {
#[tokio::test]
async fn it_imports_urls() {
let mut hydrus = common::get_hydrus();
let hydrus = common::get_hydrus();
let result = hydrus
.import()

@ -5,7 +5,7 @@ use hydrus_api::tag::Tag;
use hydrus_api::url::Url;
async fn get_url() -> Url {
let mut hydrus = common::get_hydrus();
let hydrus = common::get_hydrus();
hydrus
.url("https://www.pixiv.net/member_illust.php?illust_id=83406361&mode=medium")
.await

Loading…
Cancel
Save