feat(network): Support for editing a sonarr indexer
This commit is contained in:
@@ -9,9 +9,9 @@ use crate::{
|
|||||||
cli::{mutex_flags_or_default, mutex_flags_or_option, CliCommandHandler, Command},
|
cli::{mutex_flags_or_default, mutex_flags_or_option, CliCommandHandler, Command},
|
||||||
models::{
|
models::{
|
||||||
radarr_models::{
|
radarr_models::{
|
||||||
EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings,
|
EditCollectionParams, EditMovieParams, IndexerSettings, MinimumAvailability, RadarrSerdeable,
|
||||||
MinimumAvailability, RadarrSerdeable,
|
|
||||||
},
|
},
|
||||||
|
servarr_models::EditIndexerParams,
|
||||||
Serdeable,
|
Serdeable,
|
||||||
},
|
},
|
||||||
network::{radarr_network::RadarrEvent, NetworkTrait},
|
network::{radarr_network::RadarrEvent, NetworkTrait},
|
||||||
|
|||||||
@@ -810,9 +810,10 @@ mod tests {
|
|||||||
},
|
},
|
||||||
models::{
|
models::{
|
||||||
radarr_models::{
|
radarr_models::{
|
||||||
EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings,
|
EditCollectionParams, EditMovieParams, IndexerSettings, MinimumAvailability,
|
||||||
MinimumAvailability, RadarrSerdeable,
|
RadarrSerdeable,
|
||||||
},
|
},
|
||||||
|
servarr_models::EditIndexerParams,
|
||||||
Serdeable,
|
Serdeable,
|
||||||
},
|
},
|
||||||
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
network::{radarr_network::RadarrEvent, MockNetworkTrait, NetworkEvent},
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ mod tests {
|
|||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::radarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
|
use crate::handlers::radarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ mod tests {
|
|||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::EDIT_INDEXER_TORRENT_SELECTION_BLOCKS;
|
use crate::models::servarr_data::radarr::radarr_data::EDIT_INDEXER_TORRENT_SELECTION_BLOCKS;
|
||||||
use crate::models::BlockSelectionState;
|
use crate::models::BlockSelectionState;
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ mod tests {
|
|||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -334,7 +334,7 @@ mod tests {
|
|||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
@@ -759,7 +759,7 @@ mod tests {
|
|||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
servarr_data::radarr::radarr_data::EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, BlockSelectionState,
|
servarr_data::radarr::radarr_data::EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, BlockSelectionState,
|
||||||
};
|
};
|
||||||
@@ -1224,7 +1224,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
@@ -1281,7 +1281,7 @@ mod tests {
|
|||||||
|
|
||||||
mod test_handle_key_char {
|
mod test_handle_key_char {
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::EDIT_INDEXER_TORRENT_SELECTION_BLOCKS;
|
use crate::models::servarr_data::radarr::radarr_data::EDIT_INDEXER_TORRENT_SELECTION_BLOCKS;
|
||||||
use crate::models::BlockSelectionState;
|
use crate::models::BlockSelectionState;
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod test_handle_submit {
|
mod test_handle_submit {
|
||||||
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
RadarrData, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
RadarrData, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -179,22 +179,6 @@ pub struct EditCollectionParams {
|
|||||||
pub search_on_add: Option<bool>,
|
pub search_on_add: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Serialize, Debug, PartialEq, Eq)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct EditIndexerParams {
|
|
||||||
pub indexer_id: i64,
|
|
||||||
pub name: Option<String>,
|
|
||||||
pub enable_rss: Option<bool>,
|
|
||||||
pub enable_automatic_search: Option<bool>,
|
|
||||||
pub enable_interactive_search: Option<bool>,
|
|
||||||
pub url: Option<String>,
|
|
||||||
pub api_key: Option<String>,
|
|
||||||
pub seed_ratio: Option<String>,
|
|
||||||
pub tags: Option<Vec<i64>>,
|
|
||||||
pub priority: Option<i64>,
|
|
||||||
pub clear_tags: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Clone, Serialize, Debug, PartialEq, Eq)]
|
#[derive(Default, Clone, Serialize, Debug, PartialEq, Eq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct EditMovieParams {
|
pub struct EditMovieParams {
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
use crate::models::HorizontallyScrollableText;
|
use crate::models::HorizontallyScrollableText;
|
||||||
|
|
||||||
|
#[derive(Default, Debug, PartialEq, Eq)]
|
||||||
|
pub struct EditIndexerModal {
|
||||||
|
pub name: HorizontallyScrollableText,
|
||||||
|
pub enable_rss: Option<bool>,
|
||||||
|
pub enable_automatic_search: Option<bool>,
|
||||||
|
pub enable_interactive_search: Option<bool>,
|
||||||
|
pub url: HorizontallyScrollableText,
|
||||||
|
pub api_key: HorizontallyScrollableText,
|
||||||
|
pub seed_ratio: HorizontallyScrollableText,
|
||||||
|
pub tags: HorizontallyScrollableText,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Eq, PartialEq, Debug)]
|
#[derive(Default, Clone, Eq, PartialEq, Debug)]
|
||||||
pub struct IndexerTestResultModalItem {
|
pub struct IndexerTestResultModalItem {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use strum::IntoEnumIterator;
|
|||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
Collection, Credit, MinimumAvailability, Movie, MovieHistoryItem, MovieMonitor, RadarrRelease,
|
Collection, Credit, MinimumAvailability, Movie, MovieHistoryItem, MovieMonitor, RadarrRelease,
|
||||||
};
|
};
|
||||||
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::RadarrData;
|
use crate::models::servarr_data::radarr::radarr_data::RadarrData;
|
||||||
use crate::models::servarr_models::{Indexer, RootFolder};
|
use crate::models::servarr_models::{Indexer, RootFolder};
|
||||||
use crate::models::stateful_list::StatefulList;
|
use crate::models::stateful_list::StatefulList;
|
||||||
@@ -25,18 +26,6 @@ pub struct MovieDetailsModal {
|
|||||||
pub movie_releases: StatefulTable<RadarrRelease>,
|
pub movie_releases: StatefulTable<RadarrRelease>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Eq)]
|
|
||||||
pub struct EditIndexerModal {
|
|
||||||
pub name: HorizontallyScrollableText,
|
|
||||||
pub enable_rss: Option<bool>,
|
|
||||||
pub enable_automatic_search: Option<bool>,
|
|
||||||
pub enable_interactive_search: Option<bool>,
|
|
||||||
pub url: HorizontallyScrollableText,
|
|
||||||
pub api_key: HorizontallyScrollableText,
|
|
||||||
pub seed_ratio: HorizontallyScrollableText,
|
|
||||||
pub tags: HorizontallyScrollableText,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&RadarrData<'_>> for EditIndexerModal {
|
impl From<&RadarrData<'_>> for EditIndexerModal {
|
||||||
fn from(radarr_data: &RadarrData<'_>) -> EditIndexerModal {
|
fn from(radarr_data: &RadarrData<'_>) -> EditIndexerModal {
|
||||||
let mut edit_indexer_modal = EditIndexerModal::default();
|
let mut edit_indexer_modal = EditIndexerModal::default();
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ mod test {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_edit_indexer_modal_from_radarr_data(#[values(true, false)] seed_ratio_present: bool) {
|
fn test_edit_indexer_modal_from_radarr_data(#[values(true, false)] seed_ratio_present: bool) {
|
||||||
use crate::models::servarr_models::{Indexer, IndexerField};
|
|
||||||
|
|
||||||
let mut radarr_data = RadarrData {
|
let mut radarr_data = RadarrData {
|
||||||
tags_map: BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]),
|
tags_map: BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]),
|
||||||
..RadarrData::default()
|
..RadarrData::default()
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ use crate::models::radarr_models::{
|
|||||||
AddMovieSearchResult, BlocklistItem, Collection, CollectionMovie, DownloadRecord,
|
AddMovieSearchResult, BlocklistItem, Collection, CollectionMovie, DownloadRecord,
|
||||||
IndexerSettings, Movie, RadarrTask,
|
IndexerSettings, Movie, RadarrTask,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
use crate::models::servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem};
|
||||||
use crate::models::servarr_data::radarr::modals::{
|
use crate::models::servarr_data::radarr::modals::{
|
||||||
AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, MovieDetailsModal,
|
AddMovieModal, EditCollectionModal, EditMovieModal, MovieDetailsModal,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder};
|
use crate::models::servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder};
|
||||||
use crate::models::stateful_list::StatefulList;
|
use crate::models::stateful_list::StatefulList;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
servarr_models::RootFolder,
|
servarr_data::modals::EditIndexerModal,
|
||||||
|
servarr_models::{Indexer, RootFolder},
|
||||||
sonarr_models::{Episode, SeriesMonitor, SeriesType, SonarrHistoryItem, SonarrRelease},
|
sonarr_models::{Episode, SeriesMonitor, SeriesType, SonarrHistoryItem, SonarrRelease},
|
||||||
stateful_list::StatefulList,
|
stateful_list::StatefulList,
|
||||||
stateful_table::StatefulTable,
|
stateful_table::StatefulTable,
|
||||||
@@ -63,6 +64,84 @@ impl From<&SonarrData> for AddSeriesModal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&SonarrData> for EditIndexerModal {
|
||||||
|
fn from(sonarr_data: &SonarrData) -> EditIndexerModal {
|
||||||
|
let mut edit_indexer_modal = EditIndexerModal::default();
|
||||||
|
let Indexer {
|
||||||
|
name,
|
||||||
|
enable_rss,
|
||||||
|
enable_automatic_search,
|
||||||
|
enable_interactive_search,
|
||||||
|
tags,
|
||||||
|
fields,
|
||||||
|
..
|
||||||
|
} = sonarr_data.indexers.current_selection();
|
||||||
|
let seed_ratio_field_option = fields
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.find(|field| field.name.as_ref().unwrap() == "seedCriteria.seedRatio");
|
||||||
|
let seed_ratio_value_option = if let Some(seed_ratio_field) = seed_ratio_field_option {
|
||||||
|
seed_ratio_field.value.clone()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
edit_indexer_modal.name = name.clone().unwrap().into();
|
||||||
|
edit_indexer_modal.enable_rss = Some(*enable_rss);
|
||||||
|
edit_indexer_modal.enable_automatic_search = Some(*enable_automatic_search);
|
||||||
|
edit_indexer_modal.enable_interactive_search = Some(*enable_interactive_search);
|
||||||
|
edit_indexer_modal.url = fields
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.find(|field| field.name.as_ref().unwrap() == "baseUrl")
|
||||||
|
.unwrap()
|
||||||
|
.value
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.unwrap()
|
||||||
|
.into();
|
||||||
|
edit_indexer_modal.api_key = fields
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.find(|field| field.name.as_ref().unwrap() == "apiKey")
|
||||||
|
.unwrap()
|
||||||
|
.value
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.unwrap()
|
||||||
|
.into();
|
||||||
|
|
||||||
|
if seed_ratio_value_option.is_some() {
|
||||||
|
edit_indexer_modal.seed_ratio = seed_ratio_value_option
|
||||||
|
.unwrap()
|
||||||
|
.as_f64()
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
edit_indexer_modal.tags = tags
|
||||||
|
.iter()
|
||||||
|
.map(|tag_id| {
|
||||||
|
sonarr_data
|
||||||
|
.tags_map
|
||||||
|
.get_by_left(&tag_id.as_i64().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ")
|
||||||
|
.into();
|
||||||
|
|
||||||
|
edit_indexer_modal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct EpisodeDetailsModal {
|
pub struct EpisodeDetailsModal {
|
||||||
pub episode_details: ScrollableText,
|
pub episode_details: ScrollableText,
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::models::servarr_models::{Indexer, IndexerField};
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
servarr_data::sonarr::{modals::AddSeriesModal, sonarr_data::SonarrData},
|
servarr_data::sonarr::{modals::AddSeriesModal, sonarr_data::SonarrData},
|
||||||
servarr_models::RootFolder,
|
servarr_models::RootFolder,
|
||||||
sonarr_models::{SeriesMonitor, SeriesType},
|
sonarr_models::{SeriesMonitor, SeriesType},
|
||||||
};
|
};
|
||||||
|
use serde_json::{Number, Value};
|
||||||
|
|
||||||
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_series_modal_from_sonarr_data() {
|
fn test_add_series_modal_from_sonarr_data() {
|
||||||
@@ -55,4 +61,55 @@ mod tests {
|
|||||||
assert!(add_series_modal.tags.text.is_empty());
|
assert!(add_series_modal.tags.text.is_empty());
|
||||||
assert!(add_series_modal.use_season_folder);
|
assert!(add_series_modal.use_season_folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_modal_from_sonarr_data(#[values(true, false)] seed_ratio_present: bool) {
|
||||||
|
let mut sonarr_data = SonarrData {
|
||||||
|
tags_map: BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]),
|
||||||
|
..SonarrData::default()
|
||||||
|
};
|
||||||
|
let mut fields = vec![
|
||||||
|
IndexerField {
|
||||||
|
name: Some("baseUrl".to_owned()),
|
||||||
|
value: Some(Value::String("https://test.com".to_owned())),
|
||||||
|
},
|
||||||
|
IndexerField {
|
||||||
|
name: Some("apiKey".to_owned()),
|
||||||
|
value: Some(Value::String("1234".to_owned())),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if seed_ratio_present {
|
||||||
|
fields.push(IndexerField {
|
||||||
|
name: Some("seedCriteria.seedRatio".to_owned()),
|
||||||
|
value: Some(Value::from(1.2f64)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let indexer = Indexer {
|
||||||
|
name: Some("Test".to_owned()),
|
||||||
|
enable_rss: true,
|
||||||
|
enable_automatic_search: true,
|
||||||
|
enable_interactive_search: true,
|
||||||
|
tags: vec![Number::from(1), Number::from(2)],
|
||||||
|
fields: Some(fields),
|
||||||
|
..Indexer::default()
|
||||||
|
};
|
||||||
|
sonarr_data.indexers.set_items(vec![indexer]);
|
||||||
|
|
||||||
|
let edit_indexer_modal = EditIndexerModal::from(&sonarr_data);
|
||||||
|
|
||||||
|
assert_str_eq!(edit_indexer_modal.name.text, "Test");
|
||||||
|
assert_eq!(edit_indexer_modal.enable_rss, Some(true));
|
||||||
|
assert_eq!(edit_indexer_modal.enable_automatic_search, Some(true));
|
||||||
|
assert_eq!(edit_indexer_modal.enable_interactive_search, Some(true));
|
||||||
|
assert_str_eq!(edit_indexer_modal.url.text, "https://test.com");
|
||||||
|
assert_str_eq!(edit_indexer_modal.api_key.text, "1234");
|
||||||
|
|
||||||
|
if seed_ratio_present {
|
||||||
|
assert_str_eq!(edit_indexer_modal.seed_ratio.text, "1.2");
|
||||||
|
} else {
|
||||||
|
assert!(edit_indexer_modal.seed_ratio.text.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use chrono::{DateTime, Utc};
|
|||||||
use strum::EnumIter;
|
use strum::EnumIter;
|
||||||
|
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
servarr_data::modals::IndexerTestResultModalItem,
|
servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem},
|
||||||
servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder},
|
servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder},
|
||||||
sonarr_models::{
|
sonarr_models::{
|
||||||
AddSeriesSearchResult, BlocklistItem, DownloadRecord, IndexerSettings, Season, Series,
|
AddSeriesSearchResult, BlocklistItem, DownloadRecord, IndexerSettings, Season, Series,
|
||||||
@@ -29,6 +29,7 @@ pub struct SonarrData {
|
|||||||
pub delete_series_files: bool,
|
pub delete_series_files: bool,
|
||||||
pub downloads: StatefulTable<DownloadRecord>,
|
pub downloads: StatefulTable<DownloadRecord>,
|
||||||
pub disk_space_vec: Vec<DiskSpace>,
|
pub disk_space_vec: Vec<DiskSpace>,
|
||||||
|
pub edit_indexer_modal: Option<EditIndexerModal>,
|
||||||
pub edit_root_folder: Option<HorizontallyScrollableText>,
|
pub edit_root_folder: Option<HorizontallyScrollableText>,
|
||||||
pub history: StatefulTable<SonarrHistoryItem>,
|
pub history: StatefulTable<SonarrHistoryItem>,
|
||||||
pub indexers: StatefulTable<Indexer>,
|
pub indexers: StatefulTable<Indexer>,
|
||||||
@@ -69,6 +70,7 @@ impl Default for SonarrData {
|
|||||||
downloads: StatefulTable::default(),
|
downloads: StatefulTable::default(),
|
||||||
delete_series_files: false,
|
delete_series_files: false,
|
||||||
disk_space_vec: Vec::new(),
|
disk_space_vec: Vec::new(),
|
||||||
|
edit_indexer_modal: None,
|
||||||
edit_root_folder: None,
|
edit_root_folder: None,
|
||||||
history: StatefulTable::default(),
|
history: StatefulTable::default(),
|
||||||
indexers: StatefulTable::default(),
|
indexers: StatefulTable::default(),
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ mod tests {
|
|||||||
assert!(!sonarr_data.delete_series_files);
|
assert!(!sonarr_data.delete_series_files);
|
||||||
assert!(sonarr_data.downloads.is_empty());
|
assert!(sonarr_data.downloads.is_empty());
|
||||||
assert!(sonarr_data.disk_space_vec.is_empty());
|
assert!(sonarr_data.disk_space_vec.is_empty());
|
||||||
|
assert!(sonarr_data.edit_indexer_modal.is_none());
|
||||||
assert!(sonarr_data.edit_root_folder.is_none());
|
assert!(sonarr_data.edit_root_folder.is_none());
|
||||||
assert!(sonarr_data.history.is_empty());
|
assert!(sonarr_data.history.is_empty());
|
||||||
assert!(sonarr_data.indexers.is_empty());
|
assert!(sonarr_data.indexers.is_empty());
|
||||||
|
|||||||
@@ -89,6 +89,22 @@ pub struct DiskSpace {
|
|||||||
pub total_space: i64,
|
pub total_space: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Serialize, Debug, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct EditIndexerParams {
|
||||||
|
pub indexer_id: i64,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub enable_rss: Option<bool>,
|
||||||
|
pub enable_automatic_search: Option<bool>,
|
||||||
|
pub enable_interactive_search: Option<bool>,
|
||||||
|
pub url: Option<String>,
|
||||||
|
pub api_key: Option<String>,
|
||||||
|
pub seed_ratio: Option<String>,
|
||||||
|
pub tags: Option<Vec<i64>>,
|
||||||
|
pub priority: Option<i64>,
|
||||||
|
pub clear_tags: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct HostConfig {
|
pub struct HostConfig {
|
||||||
|
|||||||
@@ -9,18 +9,18 @@ use urlencoding::encode;
|
|||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
AddMovieBody, AddMovieOptions, AddMovieSearchResult, BlocklistResponse, Collection,
|
AddMovieBody, AddMovieOptions, AddMovieSearchResult, BlocklistResponse, Collection,
|
||||||
CollectionMovie, Credit, CreditType, DeleteMovieParams, DownloadRecord, DownloadsResponse,
|
CollectionMovie, Credit, CreditType, DeleteMovieParams, DownloadRecord, DownloadsResponse,
|
||||||
EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings, IndexerTestResult,
|
EditCollectionParams, EditMovieParams, IndexerSettings, IndexerTestResult, Movie,
|
||||||
Movie, MovieCommandBody, MovieHistoryItem, RadarrRelease, RadarrReleaseDownloadBody,
|
MovieCommandBody, MovieHistoryItem, RadarrRelease, RadarrReleaseDownloadBody, RadarrSerdeable,
|
||||||
RadarrSerdeable, RadarrTask, RadarrTaskName, SystemStatus,
|
RadarrTask, RadarrTaskName, SystemStatus,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
use crate::models::servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem};
|
||||||
use crate::models::servarr_data::radarr::modals::{
|
use crate::models::servarr_data::radarr::modals::{
|
||||||
AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, MovieDetailsModal,
|
AddMovieModal, EditCollectionModal, EditMovieModal, MovieDetailsModal,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
use crate::models::servarr_models::{
|
use crate::models::servarr_models::{
|
||||||
AddRootFolderBody, CommandBody, DiskSpace, HostConfig, Indexer, LogResponse, QualityProfile,
|
AddRootFolderBody, CommandBody, DiskSpace, EditIndexerParams, HostConfig, Indexer, LogResponse,
|
||||||
QueueEvent, RootFolder, SecurityConfig, Tag, Update,
|
QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
|
||||||
};
|
};
|
||||||
use crate::models::stateful_table::StatefulTable;
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText};
|
use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText};
|
||||||
@@ -188,9 +188,10 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.edit_collection(params)
|
.edit_collection(params)
|
||||||
.await
|
.await
|
||||||
.map(RadarrSerdeable::from),
|
.map(RadarrSerdeable::from),
|
||||||
RadarrEvent::EditIndexer(params) => {
|
RadarrEvent::EditIndexer(params) => self
|
||||||
self.edit_indexer(params).await.map(RadarrSerdeable::from)
|
.edit_radarr_indexer(params)
|
||||||
}
|
.await
|
||||||
|
.map(RadarrSerdeable::from),
|
||||||
RadarrEvent::EditMovie(params) => self.edit_movie(params).await.map(RadarrSerdeable::from),
|
RadarrEvent::EditMovie(params) => self.edit_movie(params).await.map(RadarrSerdeable::from),
|
||||||
RadarrEvent::GetAllIndexerSettings => self
|
RadarrEvent::GetAllIndexerSettings => self
|
||||||
.get_all_radarr_indexer_settings()
|
.get_all_radarr_indexer_settings()
|
||||||
@@ -882,7 +883,10 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn edit_indexer(&mut self, edit_indexer_params: Option<EditIndexerParams>) -> Result<()> {
|
async fn edit_radarr_indexer(
|
||||||
|
&mut self,
|
||||||
|
edit_indexer_params: Option<EditIndexerParams>,
|
||||||
|
) -> Result<()> {
|
||||||
let detail_event = RadarrEvent::GetIndexers;
|
let detail_event = RadarrEvent::GetIndexers;
|
||||||
let event = RadarrEvent::EditIndexer(None);
|
let event = RadarrEvent::EditIndexer(None);
|
||||||
let id = if let Some(ref params) = edit_indexer_params {
|
let id = if let Some(ref params) = edit_indexer_params {
|
||||||
|
|||||||
@@ -4053,7 +4053,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_edit_indexer_event() {
|
async fn test_handle_edit_radarr_indexer_event() {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
"enableAutomaticSearch": true,
|
"enableAutomaticSearch": true,
|
||||||
@@ -4153,7 +4153,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_edit_indexer_event_does_not_add_seed_ratio_when_seed_ratio_field_is_none_in_details(
|
async fn test_handle_edit_radarr_indexer_event_does_not_add_seed_ratio_when_seed_ratio_field_is_none_in_details(
|
||||||
) {
|
) {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
@@ -4255,7 +4255,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_edit_indexer_event_populates_the_seed_ratio_value_when_seed_ratio_field_is_present_in_details(
|
async fn test_handle_edit_radarr_indexer_event_populates_the_seed_ratio_value_when_seed_ratio_field_is_present_in_details(
|
||||||
) {
|
) {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
@@ -4371,7 +4371,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_edit_indexer_event_uses_provided_parameters() {
|
async fn test_handle_edit_radarr_indexer_event_uses_provided_parameters() {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
"enableAutomaticSearch": true,
|
"enableAutomaticSearch": true,
|
||||||
@@ -4464,7 +4464,8 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_edit_indexer_event_uses_provided_parameters_defaults_to_previous_values() {
|
async fn test_handle_edit_radarr_indexer_event_uses_provided_parameters_defaults_to_previous_values(
|
||||||
|
) {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
"enableAutomaticSearch": true,
|
"enableAutomaticSearch": true,
|
||||||
@@ -4525,7 +4526,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_edit_indexer_event_uses_provided_parameters_clears_tags_when_clear_tags_is_true(
|
async fn test_handle_edit_radarr_indexer_event_uses_provided_parameters_clears_tags_when_clear_tags_is_true(
|
||||||
) {
|
) {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ use crate::{
|
|||||||
models::{
|
models::{
|
||||||
radarr_models::IndexerTestResult,
|
radarr_models::IndexerTestResult,
|
||||||
servarr_data::{
|
servarr_data::{
|
||||||
modals::IndexerTestResultModalItem,
|
modals::{EditIndexerModal, IndexerTestResultModalItem},
|
||||||
sonarr::{
|
sonarr::{
|
||||||
modals::{AddSeriesModal, EpisodeDetailsModal, SeasonDetailsModal},
|
modals::{AddSeriesModal, EpisodeDetailsModal, SeasonDetailsModal},
|
||||||
sonarr_data::ActiveSonarrBlock,
|
sonarr_data::ActiveSonarrBlock,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
servarr_models::{
|
servarr_models::{
|
||||||
AddRootFolderBody, CommandBody, DiskSpace, HostConfig, Indexer, Language, LogResponse,
|
AddRootFolderBody, CommandBody, DiskSpace, EditIndexerParams, HostConfig, Indexer, Language,
|
||||||
QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
|
LogResponse, QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
|
||||||
},
|
},
|
||||||
sonarr_models::{
|
sonarr_models::{
|
||||||
AddSeriesBody, AddSeriesOptions, AddSeriesSearchResult, BlocklistResponse,
|
AddSeriesBody, AddSeriesOptions, AddSeriesSearchResult, BlocklistResponse,
|
||||||
@@ -51,6 +51,7 @@ pub enum SonarrEvent {
|
|||||||
DeleteTag(i64),
|
DeleteTag(i64),
|
||||||
DownloadRelease(SonarrReleaseDownloadBody),
|
DownloadRelease(SonarrReleaseDownloadBody),
|
||||||
EditAllIndexerSettings(Option<IndexerSettings>),
|
EditAllIndexerSettings(Option<IndexerSettings>),
|
||||||
|
EditIndexer(Option<EditIndexerParams>),
|
||||||
GetAllIndexerSettings,
|
GetAllIndexerSettings,
|
||||||
GetBlocklist,
|
GetBlocklist,
|
||||||
GetDownloads,
|
GetDownloads,
|
||||||
@@ -106,7 +107,9 @@ impl NetworkResource for SonarrEvent {
|
|||||||
SonarrEvent::GetEpisodes(_) | SonarrEvent::GetEpisodeDetails(_) => "/episode",
|
SonarrEvent::GetEpisodes(_) | SonarrEvent::GetEpisodeDetails(_) => "/episode",
|
||||||
SonarrEvent::GetHistory(_) | SonarrEvent::GetEpisodeHistory(_) => "/history",
|
SonarrEvent::GetHistory(_) | SonarrEvent::GetEpisodeHistory(_) => "/history",
|
||||||
SonarrEvent::GetHostConfig | SonarrEvent::GetSecurityConfig => "/config/host",
|
SonarrEvent::GetHostConfig | SonarrEvent::GetSecurityConfig => "/config/host",
|
||||||
SonarrEvent::GetIndexers | SonarrEvent::DeleteIndexer(_) => "/indexer",
|
SonarrEvent::GetIndexers | SonarrEvent::DeleteIndexer(_) | SonarrEvent::EditIndexer(_) => {
|
||||||
|
"/indexer"
|
||||||
|
}
|
||||||
SonarrEvent::GetLanguageProfiles => "/languageprofile",
|
SonarrEvent::GetLanguageProfiles => "/languageprofile",
|
||||||
SonarrEvent::GetLogs(_) => "/log",
|
SonarrEvent::GetLogs(_) => "/log",
|
||||||
SonarrEvent::GetDiskSpace => "/diskspace",
|
SonarrEvent::GetDiskSpace => "/diskspace",
|
||||||
@@ -204,6 +207,10 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.edit_all_sonarr_indexer_settings(params)
|
.edit_all_sonarr_indexer_settings(params)
|
||||||
.await
|
.await
|
||||||
.map(SonarrSerdeable::from),
|
.map(SonarrSerdeable::from),
|
||||||
|
SonarrEvent::EditIndexer(params) => self
|
||||||
|
.edit_sonarr_indexer(params)
|
||||||
|
.await
|
||||||
|
.map(SonarrSerdeable::from),
|
||||||
SonarrEvent::GetBlocklist => self.get_sonarr_blocklist().await.map(SonarrSerdeable::from),
|
SonarrEvent::GetBlocklist => self.get_sonarr_blocklist().await.map(SonarrSerdeable::from),
|
||||||
SonarrEvent::GetDownloads => self.get_sonarr_downloads().await.map(SonarrSerdeable::from),
|
SonarrEvent::GetDownloads => self.get_sonarr_downloads().await.map(SonarrSerdeable::from),
|
||||||
SonarrEvent::GetEpisodes(series_id) => self
|
SonarrEvent::GetEpisodes(series_id) => self
|
||||||
@@ -800,6 +807,261 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn edit_sonarr_indexer(
|
||||||
|
&mut self,
|
||||||
|
edit_indexer_params: Option<EditIndexerParams>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let detail_event = SonarrEvent::GetIndexers;
|
||||||
|
let event = SonarrEvent::EditIndexer(None);
|
||||||
|
let id = if let Some(ref params) = edit_indexer_params {
|
||||||
|
params.indexer_id
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.current_selection()
|
||||||
|
.id
|
||||||
|
};
|
||||||
|
info!("Updating Sonarr indexer with ID: {id}");
|
||||||
|
|
||||||
|
info!("Fetching indexer details for indexer with ID: {id}");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(
|
||||||
|
detail_event,
|
||||||
|
RequestMethod::Get,
|
||||||
|
None::<()>,
|
||||||
|
Some(format!("/{id}")),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let mut response = String::new();
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), Value>(request_props, |detailed_indexer_body, _| {
|
||||||
|
response = detailed_indexer_body.to_string()
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
info!("Constructing edit indexer body");
|
||||||
|
|
||||||
|
let mut detailed_indexer_body: Value = serde_json::from_str(&response).unwrap();
|
||||||
|
let priority = detailed_indexer_body["priority"]
|
||||||
|
.as_i64()
|
||||||
|
.expect("Unable to deserialize 'priority'");
|
||||||
|
|
||||||
|
let (
|
||||||
|
name,
|
||||||
|
enable_rss,
|
||||||
|
enable_automatic_search,
|
||||||
|
enable_interactive_search,
|
||||||
|
url,
|
||||||
|
api_key,
|
||||||
|
seed_ratio,
|
||||||
|
tags,
|
||||||
|
priority,
|
||||||
|
) = if let Some(params) = edit_indexer_params {
|
||||||
|
let seed_ratio_field_option = detailed_indexer_body["fields"]
|
||||||
|
.as_array()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.find(|field| field["name"] == "seedCriteria.seedRatio");
|
||||||
|
let name = params.name.unwrap_or(
|
||||||
|
detailed_indexer_body["name"]
|
||||||
|
.as_str()
|
||||||
|
.expect("Unable to deserialize 'name'")
|
||||||
|
.to_owned(),
|
||||||
|
);
|
||||||
|
let enable_rss = params.enable_rss.unwrap_or(
|
||||||
|
detailed_indexer_body["enableRss"]
|
||||||
|
.as_bool()
|
||||||
|
.expect("Unable to deserialize 'enableRss'"),
|
||||||
|
);
|
||||||
|
let enable_automatic_search = params.enable_automatic_search.unwrap_or(
|
||||||
|
detailed_indexer_body["enableAutomaticSearch"]
|
||||||
|
.as_bool()
|
||||||
|
.expect("Unable to deserialize 'enableAutomaticSearch"),
|
||||||
|
);
|
||||||
|
let enable_interactive_search = params.enable_interactive_search.unwrap_or(
|
||||||
|
detailed_indexer_body["enableInteractiveSearch"]
|
||||||
|
.as_bool()
|
||||||
|
.expect("Unable to deserialize 'enableInteractiveSearch'"),
|
||||||
|
);
|
||||||
|
let url = params.url.unwrap_or(
|
||||||
|
detailed_indexer_body["fields"]
|
||||||
|
.as_array()
|
||||||
|
.expect("Unable to deserialize 'fields'")
|
||||||
|
.iter()
|
||||||
|
.find(|field| field["name"] == "baseUrl")
|
||||||
|
.expect("Field 'baseUrl' was not found in the 'fields' array")
|
||||||
|
.get("value")
|
||||||
|
.unwrap_or(&json!(""))
|
||||||
|
.as_str()
|
||||||
|
.expect("Unable to deserialize 'baseUrl value'")
|
||||||
|
.to_owned(),
|
||||||
|
);
|
||||||
|
let api_key = params.api_key.unwrap_or(
|
||||||
|
detailed_indexer_body["fields"]
|
||||||
|
.as_array()
|
||||||
|
.expect("Unable to deserialize 'fields'")
|
||||||
|
.iter()
|
||||||
|
.find(|field| field["name"] == "apiKey")
|
||||||
|
.expect("Field 'apiKey' was not found in the 'fields' array")
|
||||||
|
.get("value")
|
||||||
|
.unwrap_or(&json!(""))
|
||||||
|
.as_str()
|
||||||
|
.expect("Unable to deserialize 'apiKey value'")
|
||||||
|
.to_owned(),
|
||||||
|
);
|
||||||
|
let seed_ratio = params.seed_ratio.unwrap_or_else(|| {
|
||||||
|
if let Some(seed_ratio_field) = seed_ratio_field_option {
|
||||||
|
return seed_ratio_field
|
||||||
|
.get("value")
|
||||||
|
.unwrap_or(&json!(""))
|
||||||
|
.as_str()
|
||||||
|
.expect("Unable to deserialize 'seedCriteria.seedRatio value'")
|
||||||
|
.to_owned();
|
||||||
|
}
|
||||||
|
|
||||||
|
String::new()
|
||||||
|
});
|
||||||
|
let tags = if params.clear_tags {
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
|
params.tags.unwrap_or(
|
||||||
|
detailed_indexer_body["tags"]
|
||||||
|
.as_array()
|
||||||
|
.expect("Unable to deserialize 'tags'")
|
||||||
|
.iter()
|
||||||
|
.map(|item| item.as_i64().expect("Unable to deserialize tag ID"))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let priority = params.priority.unwrap_or(priority);
|
||||||
|
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
enable_rss,
|
||||||
|
enable_automatic_search,
|
||||||
|
enable_interactive_search,
|
||||||
|
url,
|
||||||
|
api_key,
|
||||||
|
seed_ratio,
|
||||||
|
tags,
|
||||||
|
priority,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let tags = self
|
||||||
|
.app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
.text
|
||||||
|
.clone();
|
||||||
|
let tag_ids_vec = self.extract_and_add_sonarr_tag_ids_vec(tags).await;
|
||||||
|
let mut app = self.app.lock().await;
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
let EditIndexerModal {
|
||||||
|
name,
|
||||||
|
enable_rss,
|
||||||
|
enable_automatic_search,
|
||||||
|
enable_interactive_search,
|
||||||
|
url,
|
||||||
|
api_key,
|
||||||
|
seed_ratio,
|
||||||
|
..
|
||||||
|
} = app.data.sonarr_data.edit_indexer_modal.as_ref().unwrap();
|
||||||
|
|
||||||
|
(
|
||||||
|
name.text.clone(),
|
||||||
|
enable_rss.unwrap_or_default(),
|
||||||
|
enable_automatic_search.unwrap_or_default(),
|
||||||
|
enable_interactive_search.unwrap_or_default(),
|
||||||
|
url.text.clone(),
|
||||||
|
api_key.text.clone(),
|
||||||
|
seed_ratio.text.clone(),
|
||||||
|
tag_ids_vec,
|
||||||
|
priority,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
app.data.sonarr_data.edit_indexer_modal = None;
|
||||||
|
|
||||||
|
params
|
||||||
|
};
|
||||||
|
|
||||||
|
*detailed_indexer_body.get_mut("name").unwrap() = json!(name);
|
||||||
|
*detailed_indexer_body.get_mut("priority").unwrap() = json!(priority);
|
||||||
|
*detailed_indexer_body.get_mut("enableRss").unwrap() = json!(enable_rss);
|
||||||
|
*detailed_indexer_body
|
||||||
|
.get_mut("enableAutomaticSearch")
|
||||||
|
.unwrap() = json!(enable_automatic_search);
|
||||||
|
*detailed_indexer_body
|
||||||
|
.get_mut("enableInteractiveSearch")
|
||||||
|
.unwrap() = json!(enable_interactive_search);
|
||||||
|
*detailed_indexer_body
|
||||||
|
.get_mut("fields")
|
||||||
|
.unwrap()
|
||||||
|
.as_array_mut()
|
||||||
|
.unwrap()
|
||||||
|
.iter_mut()
|
||||||
|
.find(|field| field["name"] == "baseUrl")
|
||||||
|
.unwrap()
|
||||||
|
.get_mut("value")
|
||||||
|
.unwrap() = json!(url);
|
||||||
|
*detailed_indexer_body
|
||||||
|
.get_mut("fields")
|
||||||
|
.unwrap()
|
||||||
|
.as_array_mut()
|
||||||
|
.unwrap()
|
||||||
|
.iter_mut()
|
||||||
|
.find(|field| field["name"] == "apiKey")
|
||||||
|
.unwrap()
|
||||||
|
.get_mut("value")
|
||||||
|
.unwrap() = json!(api_key);
|
||||||
|
*detailed_indexer_body.get_mut("tags").unwrap() = json!(tags);
|
||||||
|
let seed_ratio_field_option = detailed_indexer_body
|
||||||
|
.get_mut("fields")
|
||||||
|
.unwrap()
|
||||||
|
.as_array_mut()
|
||||||
|
.unwrap()
|
||||||
|
.iter_mut()
|
||||||
|
.find(|field| field["name"] == "seedCriteria.seedRatio");
|
||||||
|
if let Some(seed_ratio_field) = seed_ratio_field_option {
|
||||||
|
seed_ratio_field
|
||||||
|
.as_object_mut()
|
||||||
|
.unwrap()
|
||||||
|
.insert("value".to_string(), json!(seed_ratio));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Edit indexer body: {detailed_indexer_body:?}");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(
|
||||||
|
event,
|
||||||
|
RequestMethod::Put,
|
||||||
|
Some(detailed_indexer_body),
|
||||||
|
Some(format!("/{id}")),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<Value, ()>(request_props, |_, _| ())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_all_sonarr_indexer_settings(&mut self) -> Result<IndexerSettings> {
|
async fn get_all_sonarr_indexer_settings(&mut self) -> Result<IndexerSettings> {
|
||||||
info!("Fetching Sonarr indexer settings");
|
info!("Fetching Sonarr indexer settings");
|
||||||
let event = SonarrEvent::GetAllIndexerSettings;
|
let event = SonarrEvent::GetAllIndexerSettings;
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ mod test {
|
|||||||
|
|
||||||
use crate::app::{App, ServarrConfig};
|
use crate::app::{App, ServarrConfig};
|
||||||
use crate::models::radarr_models::IndexerTestResult;
|
use crate::models::radarr_models::IndexerTestResult;
|
||||||
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
use crate::models::servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem};
|
||||||
use crate::models::servarr_data::sonarr::modals::{
|
use crate::models::servarr_data::sonarr::modals::{
|
||||||
AddSeriesModal, EpisodeDetailsModal, SeasonDetailsModal,
|
AddSeriesModal, EpisodeDetailsModal, SeasonDetailsModal,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||||
use crate::models::servarr_models::{
|
use crate::models::servarr_models::{
|
||||||
DiskSpace, HostConfig, Indexer, IndexerField, Language, LogResponse, Quality, QualityProfile,
|
DiskSpace, EditIndexerParams, HostConfig, Indexer, IndexerField, Language, LogResponse,
|
||||||
QualityWrapper, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
|
Quality, QualityProfile, QualityWrapper, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
|
||||||
};
|
};
|
||||||
use crate::models::sonarr_models::{
|
use crate::models::sonarr_models::{
|
||||||
BlocklistItem, DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode, EpisodeFile,
|
BlocklistItem, DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode, EpisodeFile,
|
||||||
@@ -205,7 +205,12 @@ mod test {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_resource_indexer(
|
fn test_resource_indexer(
|
||||||
#[values(SonarrEvent::GetIndexers, SonarrEvent::DeleteIndexer(None))] event: SonarrEvent,
|
#[values(
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
SonarrEvent::DeleteIndexer(None),
|
||||||
|
SonarrEvent::EditIndexer(None)
|
||||||
|
)]
|
||||||
|
event: SonarrEvent,
|
||||||
) {
|
) {
|
||||||
assert_str_eq!(event.resource(), "/indexer");
|
assert_str_eq!(event.resource(), "/indexer");
|
||||||
}
|
}
|
||||||
@@ -1126,6 +1131,565 @@ mod test {
|
|||||||
async_server.assert_async().await;
|
async_server.assert_async().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_edit_sonarr_indexer_event() {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected_indexer_edit_body_json = json!({
|
||||||
|
"enableRss": false,
|
||||||
|
"enableAutomaticSearch": false,
|
||||||
|
"enableInteractiveSearch": false,
|
||||||
|
"name": "Test Update",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://localhost:9696/1/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "test1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1, 2],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_edit_server = server
|
||||||
|
.mock(
|
||||||
|
"PUT",
|
||||||
|
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(202)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(expected_indexer_edit_body_json))
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
{
|
||||||
|
let mut app = app_arc.lock().await;
|
||||||
|
app.data.sonarr_data.tags_map =
|
||||||
|
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
|
||||||
|
let edit_indexer_modal = EditIndexerModal {
|
||||||
|
name: "Test Update".into(),
|
||||||
|
enable_rss: Some(false),
|
||||||
|
enable_automatic_search: Some(false),
|
||||||
|
enable_interactive_search: Some(false),
|
||||||
|
url: "https://localhost:9696/1/".into(),
|
||||||
|
api_key: "test1234".into(),
|
||||||
|
seed_ratio: "1.3".into(),
|
||||||
|
tags: "usenet, testing".into(),
|
||||||
|
};
|
||||||
|
app.data.sonarr_data.edit_indexer_modal = Some(edit_indexer_modal);
|
||||||
|
app.data.sonarr_data.indexers.set_items(vec![indexer()]);
|
||||||
|
}
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
assert!(network
|
||||||
|
.handle_sonarr_event(SonarrEvent::EditIndexer(None))
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_edit_server.assert_async().await;
|
||||||
|
|
||||||
|
let app = app_arc.lock().await;
|
||||||
|
assert!(app.data.sonarr_data.edit_indexer_modal.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_edit_sonarr_indexer_event_does_not_add_seed_ratio_when_seed_ratio_field_is_none_in_details(
|
||||||
|
) {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected_indexer_edit_body_json = json!({
|
||||||
|
"enableRss": false,
|
||||||
|
"enableAutomaticSearch": false,
|
||||||
|
"enableInteractiveSearch": false,
|
||||||
|
"name": "Test Update",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://localhost:9696/1/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "test1234",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1, 2],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_edit_server = server
|
||||||
|
.mock(
|
||||||
|
"PUT",
|
||||||
|
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(202)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(expected_indexer_edit_body_json))
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
{
|
||||||
|
let mut app = app_arc.lock().await;
|
||||||
|
app.data.sonarr_data.tags_map =
|
||||||
|
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
|
||||||
|
let edit_indexer_modal = EditIndexerModal {
|
||||||
|
name: "Test Update".into(),
|
||||||
|
enable_rss: Some(false),
|
||||||
|
enable_automatic_search: Some(false),
|
||||||
|
enable_interactive_search: Some(false),
|
||||||
|
url: "https://localhost:9696/1/".into(),
|
||||||
|
api_key: "test1234".into(),
|
||||||
|
seed_ratio: "1.3".into(),
|
||||||
|
tags: "usenet, testing".into(),
|
||||||
|
};
|
||||||
|
app.data.sonarr_data.edit_indexer_modal = Some(edit_indexer_modal);
|
||||||
|
let mut indexer = indexer();
|
||||||
|
indexer.fields = Some(
|
||||||
|
indexer
|
||||||
|
.fields
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|field| field.name != Some("seedCriteria.seedRatio".to_string()))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
app.data.sonarr_data.indexers.set_items(vec![indexer]);
|
||||||
|
}
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
assert!(network
|
||||||
|
.handle_sonarr_event(SonarrEvent::EditIndexer(None))
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_edit_server.assert_async().await;
|
||||||
|
|
||||||
|
let app = app_arc.lock().await;
|
||||||
|
assert!(app.data.sonarr_data.edit_indexer_modal.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_edit_sonarr_indexer_event_populates_the_seed_ratio_value_when_seed_ratio_field_is_present_in_details(
|
||||||
|
) {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected_indexer_edit_body_json = json!({
|
||||||
|
"enableRss": false,
|
||||||
|
"enableAutomaticSearch": false,
|
||||||
|
"enableInteractiveSearch": false,
|
||||||
|
"name": "Test Update",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://localhost:9696/1/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "test1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1, 2],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_edit_server = server
|
||||||
|
.mock(
|
||||||
|
"PUT",
|
||||||
|
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(202)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(expected_indexer_edit_body_json))
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
{
|
||||||
|
let mut app = app_arc.lock().await;
|
||||||
|
app.data.sonarr_data.tags_map =
|
||||||
|
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
|
||||||
|
let edit_indexer_modal = EditIndexerModal {
|
||||||
|
name: "Test Update".into(),
|
||||||
|
enable_rss: Some(false),
|
||||||
|
enable_automatic_search: Some(false),
|
||||||
|
enable_interactive_search: Some(false),
|
||||||
|
url: "https://localhost:9696/1/".into(),
|
||||||
|
api_key: "test1234".into(),
|
||||||
|
seed_ratio: "1.3".into(),
|
||||||
|
tags: "usenet, testing".into(),
|
||||||
|
};
|
||||||
|
app.data.sonarr_data.edit_indexer_modal = Some(edit_indexer_modal);
|
||||||
|
let mut indexer = indexer();
|
||||||
|
indexer.fields = Some(
|
||||||
|
indexer
|
||||||
|
.fields
|
||||||
|
.unwrap()
|
||||||
|
.into_iter()
|
||||||
|
.map(|mut field| {
|
||||||
|
if field.name == Some("seedCriteria.seedRatio".to_string()) {
|
||||||
|
field.value = None;
|
||||||
|
field
|
||||||
|
} else {
|
||||||
|
field
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
app.data.sonarr_data.indexers.set_items(vec![indexer]);
|
||||||
|
}
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
assert!(network
|
||||||
|
.handle_sonarr_event(SonarrEvent::EditIndexer(None))
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_edit_server.assert_async().await;
|
||||||
|
|
||||||
|
let app = app_arc.lock().await;
|
||||||
|
assert!(app.data.sonarr_data.edit_indexer_modal.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_edit_sonarr_indexer_event_uses_provided_parameters() {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected_indexer_edit_body_json = json!({
|
||||||
|
"enableRss": false,
|
||||||
|
"enableAutomaticSearch": false,
|
||||||
|
"enableInteractiveSearch": false,
|
||||||
|
"name": "Test Update",
|
||||||
|
"priority": 25,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://localhost:9696/1/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "test1234",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.3",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1, 2],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let edit_indexer_params = EditIndexerParams {
|
||||||
|
indexer_id: 1,
|
||||||
|
name: Some("Test Update".to_owned()),
|
||||||
|
enable_rss: Some(false),
|
||||||
|
enable_automatic_search: Some(false),
|
||||||
|
enable_interactive_search: Some(false),
|
||||||
|
url: Some("https://localhost:9696/1/".to_owned()),
|
||||||
|
api_key: Some("test1234".to_owned()),
|
||||||
|
seed_ratio: Some("1.3".to_owned()),
|
||||||
|
tags: Some(vec![1, 2]),
|
||||||
|
priority: Some(25),
|
||||||
|
..EditIndexerParams::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_edit_server = server
|
||||||
|
.mock(
|
||||||
|
"PUT",
|
||||||
|
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(202)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(expected_indexer_edit_body_json))
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
assert!(network
|
||||||
|
.handle_sonarr_event(SonarrEvent::EditIndexer(Some(edit_indexer_params)))
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_edit_server.assert_async().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_edit_sonarr_indexer_event_uses_provided_parameters_defaults_to_previous_values(
|
||||||
|
) {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let edit_indexer_params = EditIndexerParams {
|
||||||
|
indexer_id: 1,
|
||||||
|
..EditIndexerParams::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json.clone()),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_edit_server = server
|
||||||
|
.mock(
|
||||||
|
"PUT",
|
||||||
|
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(202)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(indexer_details_json))
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
assert!(network
|
||||||
|
.handle_sonarr_event(SonarrEvent::EditIndexer(Some(edit_indexer_params)))
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_edit_server.assert_async().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_edit_sonarr_indexer_event_uses_provided_parameters_clears_tags_when_clear_tags_is_true(
|
||||||
|
) {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1, 2],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let expected_edit_indexer_body = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"priority": 1,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let edit_indexer_params = EditIndexerParams {
|
||||||
|
indexer_id: 1,
|
||||||
|
clear_tags: true,
|
||||||
|
..EditIndexerParams::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_edit_server = server
|
||||||
|
.mock(
|
||||||
|
"PUT",
|
||||||
|
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(202)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(expected_edit_indexer_body))
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
assert!(network
|
||||||
|
.handle_sonarr_event(SonarrEvent::EditIndexer(Some(edit_indexer_params)))
|
||||||
|
.await
|
||||||
|
.is_ok());
|
||||||
|
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_edit_server.assert_async().await;
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_get_sonarr_blocklist_event(#[values(true, false)] use_custom_sorting: bool) {
|
async fn test_handle_get_sonarr_blocklist_event(#[values(true, false)] use_custom_sorting: bool) {
|
||||||
|
|||||||
Reference in New Issue
Block a user