Added the ability to add and delete root folders, and added a body to the error message logs and dialog box if a body is returned from the Servarr

This commit is contained in:
2023-08-08 10:50:06 -06:00
parent 9142d5ab3e
commit a564710aee
7 changed files with 437 additions and 21 deletions
+48 -7
View File
@@ -3,6 +3,7 @@ use std::sync::Arc;
use anyhow::anyhow;
use log::{debug, error};
use regex::Regex;
use reqwest::{Client, RequestBuilder};
use serde::de::DeserializeOwned;
use serde::Serialize;
@@ -71,13 +72,21 @@ impl<'a> Network<'a> {
RequestMethod::Delete | RequestMethod::Put => (),
}
} else {
let status = response.status();
let whitespace_regex = Regex::new(r"\s+").unwrap();
let response_body = response.text().await.unwrap_or_default();
let error_body = whitespace_regex
.replace_all(&response_body.replace('\n', " "), " ")
.to_string();
error!(
"Request failed. Received {} response code",
response.status()
"Request failed. Received {} response code with body: {}",
status, response_body
);
self.app.lock().await.handle_error(anyhow!(
"Request failed. Received {} response code",
response.status()
"Request failed. Received {} response code with body: {}",
status,
error_body
));
}
}
@@ -337,7 +346,31 @@ mod tests {
async_server.assert_async().await;
assert_str_eq!(
app_arc.lock().await.error.text,
"Request failed. Received 404 Not Found response code"
r#"Request failed. Received 404 Not Found response code with body: { "value": "Test" }"#
);
}
#[tokio::test]
async fn test_handle_request_non_success_code_empty_response_body() {
let (async_server, app_arc, server) = mock_api(RequestMethod::Post, 404, false).await;
let network = Network::new(reqwest::Client::new(), &app_arc);
network
.handle_request::<(), Test>(
RequestProps {
uri: format!("{}/test", server.url()),
method: RequestMethod::Post,
body: None,
api_token: "test1234".to_owned(),
},
|response, mut app| app.error = HorizontallyScrollableText::from(response.value),
)
.await;
async_server.assert_async().await;
assert_str_eq!(
app_arc.lock().await.error.text,
r#"Request failed. Received 404 Not Found response code with body: "#
);
}
@@ -360,7 +393,11 @@ mod tests {
let mut body = None::<Test>;
if request_method == RequestMethod::Post {
async_server = async_server.with_body(r#"{ "value": "Test" }"#);
async_server = async_server.with_body(
r#"{
"value": "Test"
}"#,
);
body = Some(Test {
value: "Test".to_owned(),
});
@@ -402,7 +439,11 @@ mod tests {
.with_status(response_status);
if has_response_body {
async_server = async_server.with_body(r#"{ "value": "Test" }"#);
async_server = async_server.with_body(
r#"{
"value": "Test"
}"#,
);
}
async_server = async_server.create_async().await;
+126 -6
View File
@@ -9,9 +9,10 @@ use urlencoding::encode;
use crate::app::radarr::ActiveRadarrBlock;
use crate::app::RadarrConfig;
use crate::models::radarr_models::{
AddMovieBody, AddMovieSearchResult, AddOptions, Collection, CollectionMovie, CommandBody, Credit,
CreditType, DiskSpace, DownloadRecord, DownloadsResponse, Movie, MovieCommandBody,
MovieHistoryItem, QualityProfile, Release, ReleaseDownloadBody, RootFolder, SystemStatus, Tag,
AddMovieBody, AddMovieSearchResult, AddOptions, AddRootFolderBody, Collection, CollectionMovie,
CommandBody, Credit, CreditType, DiskSpace, DownloadRecord, DownloadsResponse, Movie,
MovieCommandBody, MovieHistoryItem, QualityProfile, Release, ReleaseDownloadBody, RootFolder,
SystemStatus, Tag,
};
use crate::models::{Route, ScrollableText};
use crate::network::{Network, NetworkEvent, RequestMethod, RequestProps};
@@ -20,8 +21,10 @@ use crate::utils::{convert_runtime, convert_to_gb};
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum RadarrEvent {
AddMovie,
AddRootFolder,
DeleteDownload,
DeleteMovie,
DeleteRootFolder,
DownloadRelease,
EditMovie,
EditCollection,
@@ -62,7 +65,9 @@ impl RadarrEvent {
RadarrEvent::GetOverview => "/diskspace",
RadarrEvent::GetQualityProfiles => "/qualityprofile",
RadarrEvent::GetReleases | RadarrEvent::DownloadRelease => "/release",
RadarrEvent::GetRootFolders => "/rootfolder",
RadarrEvent::AddRootFolder | RadarrEvent::GetRootFolders | RadarrEvent::DeleteRootFolder => {
"/rootfolder"
}
RadarrEvent::GetStatus => "/system/status",
RadarrEvent::GetTags => "/tag",
RadarrEvent::TriggerAutomaticSearch
@@ -85,8 +90,10 @@ impl<'a> Network<'a> {
pub async fn handle_radarr_event(&self, radarr_event: RadarrEvent) {
match radarr_event {
RadarrEvent::AddMovie => self.add_movie().await,
RadarrEvent::AddRootFolder => self.add_root_folder().await,
RadarrEvent::DeleteMovie => self.delete_movie().await,
RadarrEvent::DeleteDownload => self.delete_download().await,
RadarrEvent::DeleteRootFolder => self.delete_root_folder().await,
RadarrEvent::DownloadRelease => self.download_release().await,
RadarrEvent::EditMovie => self.edit_movie().await,
RadarrEvent::EditCollection => self.edit_collection().await,
@@ -726,6 +733,42 @@ impl<'a> Network<'a> {
.await;
}
async fn delete_root_folder(&self) {
let root_folder_id = self
.app
.lock()
.await
.data
.radarr_data
.root_folders
.current_selection()
.id
.as_u64()
.unwrap();
info!(
"Deleting Radarr root folder for folder with id: {}",
root_folder_id
);
let request_props = self
.radarr_request_props_from(
format!(
"{}/{}",
RadarrEvent::DeleteRootFolder.resource(),
root_folder_id
)
.as_str(),
RequestMethod::Delete,
None::<()>,
)
.await;
self
.handle_request::<(), ()>(request_props, |_, _| ())
.await;
}
async fn add_movie(&self) {
info!("Adding new movie to Radarr");
let body = {
@@ -804,6 +847,27 @@ impl<'a> Network<'a> {
.await;
}
async fn add_root_folder(&self) {
info!("Adding new root folder to Radarr");
let body = AddRootFolderBody {
path: self.app.lock().await.data.radarr_data.edit_path.drain(),
};
debug!("Add root folder body: {:?}", body);
let request_props = self
.radarr_request_props_from(
RadarrEvent::AddRootFolder.resource(),
RequestMethod::Post,
Some(body),
)
.await;
self
.handle_request::<AddRootFolderBody, Value>(request_props, |_, _| ())
.await;
}
async fn edit_movie(&self) {
info!("Editing Radarr movie");
@@ -2178,9 +2242,34 @@ mod test {
async_server.assert_async().await;
}
#[tokio::test]
async fn test_handle_delete_root_folder_event() {
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Delete,
None,
None,
format!("{}/1", RadarrEvent::DeleteRootFolder.resource()).as_str(),
)
.await;
app_arc
.lock()
.await
.data
.radarr_data
.root_folders
.set_items(vec![root_folder()]);
let network = Network::new(reqwest::Client::new(), &app_arc);
network
.handle_radarr_event(RadarrEvent::DeleteRootFolder)
.await;
async_server.assert_async().await;
}
#[rstest]
#[tokio::test]
async fn test_handle_add_movie_event(#[values(true, false)] collection_details_context: bool) {
async fn test_handle_add_movie_event(#[values(true, false)] movie_details_context: bool) {
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Post,
Some(json!({
@@ -2239,7 +2328,7 @@ mod test {
.radarr_data
.minimum_availability_list
.set_items(Vec::from_iter(MinimumAvailability::iter()));
if collection_details_context {
if movie_details_context {
app
.data
.radarr_data
@@ -2261,6 +2350,37 @@ mod test {
async_server.assert_async().await;
}
#[tokio::test]
async fn test_handle_add_root_folder_event() {
let (async_server, app_arc, _server) = mock_radarr_api(
RequestMethod::Post,
Some(json!({
"path": "/nfs/test"
})),
None,
RadarrEvent::AddRootFolder.resource(),
)
.await;
app_arc.lock().await.data.radarr_data.edit_path =
HorizontallyScrollableText::from("/nfs/test".to_owned());
let network = Network::new(reqwest::Client::new(), &app_arc);
network
.handle_radarr_event(RadarrEvent::AddRootFolder)
.await;
async_server.assert_async().await;
assert!(app_arc
.lock()
.await
.data
.radarr_data
.edit_path
.text
.is_empty());
}
#[tokio::test]
async fn test_handle_edit_movie_event() {
let mut expected_body: Value = serde_json::from_str(MOVIE_JSON).unwrap();