diff --git a/src/handlers/radarr_handlers/library/add_movie_handler_tests.rs b/src/handlers/radarr_handlers/library/add_movie_handler_tests.rs index 7da2d8f..c0797ec 100644 --- a/src/handlers/radarr_handlers/library/add_movie_handler_tests.rs +++ b/src/handlers/radarr_handlers/library/add_movie_handler_tests.rs @@ -8,10 +8,9 @@ mod tests { use crate::event::Key; use crate::handlers::radarr_handlers::library::add_movie_handler::AddMovieHandler; use crate::handlers::KeyEventHandler; - use crate::models::radarr_models::{ - AddMovieSearchResult, MinimumAvailability, Monitor, RootFolder, - }; + use crate::models::radarr_models::{AddMovieSearchResult, MinimumAvailability, Monitor}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS}; + use crate::models::servarr_models::RootFolder; use crate::models::HorizontallyScrollableText; mod test_handle_scroll_up_and_down { diff --git a/src/handlers/radarr_handlers/root_folders/root_folders_handler_tests.rs b/src/handlers/radarr_handlers/root_folders/root_folders_handler_tests.rs index 8a62dde..fc9bd65 100644 --- a/src/handlers/radarr_handlers/root_folders/root_folders_handler_tests.rs +++ b/src/handlers/radarr_handlers/root_folders/root_folders_handler_tests.rs @@ -8,14 +8,14 @@ mod tests { use crate::event::Key; use crate::handlers::radarr_handlers::root_folders::RootFoldersHandler; use crate::handlers::KeyEventHandler; - use crate::models::radarr_models::RootFolder; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ROOT_FOLDERS_BLOCKS}; + use crate::models::servarr_models::RootFolder; use crate::models::HorizontallyScrollableText; mod test_handle_scroll_up_and_down { use rstest::rstest; - use crate::models::radarr_models::RootFolder; + use crate::models::servarr_models::RootFolder; use crate::{simple_stateful_iterable_vec, test_iterable_scroll}; use super::*; @@ -63,7 +63,7 @@ mod tests { use pretty_assertions::assert_eq; - use crate::models::radarr_models::RootFolder; + use crate::models::servarr_models::RootFolder; use crate::{extended_stateful_iterable_vec, test_iterable_home_and_end}; use super::*; diff --git a/src/models/radarr_models.rs b/src/models/radarr_models.rs index 286f3ee..283eeef 100644 --- a/src/models/radarr_models.rs +++ b/src/models/radarr_models.rs @@ -11,7 +11,7 @@ use crate::{models::HorizontallyScrollableText, serde_enum_from}; use super::servarr_models::{ HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper, QueueEvent, Release, - SecurityConfig, + RootFolder, SecurityConfig, }; use super::{EnumDisplayStyle, Serdeable}; @@ -440,18 +440,6 @@ pub struct ReleaseDownloadBody { pub movie_id: i64, } -#[derive(Default, Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] -#[serde(rename_all = "camelCase")] -pub struct RootFolder { - #[serde(deserialize_with = "super::from_i64")] - pub id: i64, - pub path: String, - pub accessible: bool, - #[serde(deserialize_with = "super::from_i64")] - pub free_space: i64, - pub unmapped_folders: Option>, -} - #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct SystemStatus { @@ -504,12 +492,6 @@ impl Display for TaskName { } } -#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)] -pub struct UnmappedFolder { - pub name: String, - pub path: String, -} - #[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Update { diff --git a/src/models/radarr_models_tests.rs b/src/models/radarr_models_tests.rs index 8cb1643..eb07c6b 100644 --- a/src/models/radarr_models_tests.rs +++ b/src/models/radarr_models_tests.rs @@ -8,9 +8,9 @@ mod tests { AddMovieSearchResult, BlocklistItem, BlocklistResponse, Collection, Credit, DiskSpace, DownloadRecord, DownloadsResponse, Indexer, IndexerSettings, IndexerTestResult, MinimumAvailability, Monitor, Movie, MovieHistoryItem, QualityProfile, RadarrSerdeable, - Release, RootFolder, SystemStatus, Tag, Task, TaskName, Update, + Release, SystemStatus, Tag, Task, TaskName, Update, }, - servarr_models::{HostConfig, Log, LogResponse, QueueEvent, SecurityConfig}, + servarr_models::{HostConfig, Log, LogResponse, QueueEvent, RootFolder, SecurityConfig}, EnumDisplayStyle, Serdeable, }; diff --git a/src/models/servarr_data/radarr/modals.rs b/src/models/servarr_data/radarr/modals.rs index 8cfce95..3f73e3e 100644 --- a/src/models/servarr_data/radarr/modals.rs +++ b/src/models/servarr_data/radarr/modals.rs @@ -1,10 +1,10 @@ use strum::IntoEnumIterator; use crate::models::radarr_models::{ - Collection, Credit, MinimumAvailability, Monitor, Movie, MovieHistoryItem, RootFolder, + Collection, Credit, MinimumAvailability, Monitor, Movie, MovieHistoryItem, }; use crate::models::servarr_data::radarr::radarr_data::RadarrData; -use crate::models::servarr_models::{Indexer, Release}; +use crate::models::servarr_models::{Indexer, Release, RootFolder}; use crate::models::stateful_list::StatefulList; use crate::models::stateful_table::StatefulTable; use crate::models::{HorizontallyScrollableText, ScrollableText}; diff --git a/src/models/servarr_data/radarr/modals_tests.rs b/src/models/servarr_data/radarr/modals_tests.rs index 5da0298..62faa71 100644 --- a/src/models/servarr_data/radarr/modals_tests.rs +++ b/src/models/servarr_data/radarr/modals_tests.rs @@ -1,12 +1,12 @@ #[cfg(test)] mod test { - use crate::models::radarr_models::{Collection, MinimumAvailability, Monitor, Movie, RootFolder}; + use crate::models::radarr_models::{Collection, MinimumAvailability, Monitor, Movie}; use crate::models::servarr_data::radarr::modals::{ AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, }; use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data; use crate::models::servarr_data::radarr::radarr_data::RadarrData; - use crate::models::servarr_models::{Indexer, IndexerField}; + use crate::models::servarr_models::{Indexer, IndexerField, RootFolder}; use crate::models::stateful_table::StatefulTable; use bimap::BiMap; use pretty_assertions::{assert_eq, assert_str_eq}; diff --git a/src/models/servarr_data/radarr/radarr_data.rs b/src/models/servarr_data/radarr/radarr_data.rs index e3d4a7c..4f7e6a4 100644 --- a/src/models/servarr_data/radarr/radarr_data.rs +++ b/src/models/servarr_data/radarr/radarr_data.rs @@ -7,13 +7,13 @@ use crate::app::radarr::radarr_context_clues::{ }; use crate::models::radarr_models::{ AddMovieSearchResult, BlocklistItem, Collection, CollectionMovie, DiskSpace, DownloadRecord, - IndexerSettings, Movie, RootFolder, Task, + IndexerSettings, Movie, Task, }; use crate::models::servarr_data::radarr::modals::{ AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, IndexerTestResultModalItem, MovieDetailsModal, }; -use crate::models::servarr_models::{Indexer, QueueEvent}; +use crate::models::servarr_models::{Indexer, QueueEvent, RootFolder}; use crate::models::stateful_list::StatefulList; use crate::models::stateful_table::StatefulTable; use crate::models::{ diff --git a/src/models/servarr_data/sonarr/sonarr_data.rs b/src/models/servarr_data/sonarr/sonarr_data.rs index c3434ce..cd274d2 100644 --- a/src/models/servarr_data/sonarr/sonarr_data.rs +++ b/src/models/servarr_data/sonarr/sonarr_data.rs @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc}; use strum::EnumIter; use crate::models::{ - servarr_models::{Indexer, QueueEvent}, + servarr_models::{Indexer, QueueEvent, RootFolder}, sonarr_models::{ BlocklistItem, DownloadRecord, IndexerSettings, Season, Series, SonarrHistoryItem, }, @@ -27,6 +27,7 @@ pub struct SonarrData { pub logs: StatefulList, pub quality_profile_map: BiMap, pub queued_events: StatefulTable, + pub root_folders: StatefulTable, pub seasons: StatefulTable, pub season_details_modal: Option, pub series: StatefulTable, @@ -46,6 +47,7 @@ impl Default for SonarrData { logs: StatefulList::default(), quality_profile_map: BiMap::new(), queued_events: StatefulTable::default(), + root_folders: StatefulTable::default(), seasons: StatefulTable::default(), season_details_modal: None, series: StatefulTable::default(), diff --git a/src/models/servarr_data/sonarr/sonarr_data_tests.rs b/src/models/servarr_data/sonarr/sonarr_data_tests.rs index 90051cb..60fecc2 100644 --- a/src/models/servarr_data/sonarr/sonarr_data_tests.rs +++ b/src/models/servarr_data/sonarr/sonarr_data_tests.rs @@ -42,6 +42,7 @@ mod tests { assert!(sonarr_data.logs.is_empty()); assert!(sonarr_data.quality_profile_map.is_empty()); assert!(sonarr_data.queued_events.is_empty()); + assert!(sonarr_data.root_folders.is_empty()); assert!(sonarr_data.seasons.is_empty()); assert!(sonarr_data.season_details_modal.is_none()); assert!(sonarr_data.series.is_empty()); diff --git a/src/models/servarr_models.rs b/src/models/servarr_models.rs index 82392d7..12c5234 100644 --- a/src/models/servarr_models.rs +++ b/src/models/servarr_models.rs @@ -197,6 +197,18 @@ pub struct Release { pub quality: QualityWrapper, } +#[derive(Default, Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct RootFolder { + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, + pub path: String, + pub accessible: bool, + #[serde(deserialize_with = "super::from_i64")] + pub free_space: i64, + pub unmapped_folders: Option>, +} + #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct SecurityConfig { @@ -210,3 +222,9 @@ pub struct SecurityConfig { pub api_key: String, pub certificate_validation: CertificateValidation, } + +#[derive(Serialize, Deserialize, Default, Debug, Clone, Eq, PartialEq)] +pub struct UnmappedFolder { + pub name: String, + pub path: String, +} diff --git a/src/models/sonarr_models.rs b/src/models/sonarr_models.rs index aa22e2b..edba686 100644 --- a/src/models/sonarr_models.rs +++ b/src/models/sonarr_models.rs @@ -12,7 +12,7 @@ use crate::serde_enum_from; use super::{ servarr_models::{ HostConfig, Indexer, Language, LogResponse, QualityProfile, QualityWrapper, QueueEvent, - Release, SecurityConfig, + Release, RootFolder, SecurityConfig, }, EnumDisplayStyle, HorizontallyScrollableText, Serdeable, }; @@ -402,6 +402,7 @@ pub enum SonarrSerdeable { QualityProfiles(Vec), QueueEvents(Vec), Releases(Vec), + RootFolders(Vec), SecurityConfig(SecurityConfig), SeriesVec(Vec), Series(Series), @@ -436,6 +437,7 @@ serde_enum_from!( QualityProfiles(Vec), QueueEvents(Vec), Releases(Vec), + RootFolders(Vec), SecurityConfig(SecurityConfig), SeriesVec(Vec), Series(Series), diff --git a/src/models/sonarr_models_tests.rs b/src/models/sonarr_models_tests.rs index b65779f..8bee1a1 100644 --- a/src/models/sonarr_models_tests.rs +++ b/src/models/sonarr_models_tests.rs @@ -5,7 +5,8 @@ mod tests { use crate::models::{ servarr_models::{ - HostConfig, Indexer, Log, LogResponse, QualityProfile, QueueEvent, Release, SecurityConfig, + HostConfig, Indexer, Log, LogResponse, QualityProfile, QueueEvent, Release, RootFolder, + SecurityConfig, }, sonarr_models::{ BlocklistItem, BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, @@ -343,6 +344,18 @@ mod tests { assert_eq!(sonarr_serdeable, SonarrSerdeable::Releases(releases)); } + #[test] + fn test_sonarr_serdeable_from_root_folders() { + let root_folders = vec![RootFolder { + id: 1, + ..RootFolder::default() + }]; + + let sonarr_serdeable: SonarrSerdeable = root_folders.clone().into(); + + assert_eq!(sonarr_serdeable, SonarrSerdeable::RootFolders(root_folders)); + } + #[test] fn test_sonarr_serdeable_from_security_config() { let security_config = SecurityConfig { diff --git a/src/network/radarr_network.rs b/src/network/radarr_network.rs index f02965a..f7599a0 100644 --- a/src/network/radarr_network.rs +++ b/src/network/radarr_network.rs @@ -11,7 +11,7 @@ use crate::models::radarr_models::{ CollectionMovie, CommandBody, Credit, CreditType, DeleteMovieParams, DiskSpace, DownloadRecord, DownloadsResponse, EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings, IndexerTestResult, Movie, MovieCommandBody, MovieHistoryItem, RadarrSerdeable, - ReleaseDownloadBody, RootFolder, SystemStatus, Tag, Task, TaskName, Update, + ReleaseDownloadBody, SystemStatus, Tag, Task, TaskName, Update, }; use crate::models::servarr_data::radarr::modals::{ AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, IndexerTestResultModalItem, @@ -19,7 +19,7 @@ use crate::models::servarr_data::radarr::modals::{ }; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_models::{ - HostConfig, Indexer, LogResponse, QualityProfile, QueueEvent, Release, SecurityConfig, + HostConfig, Indexer, LogResponse, QualityProfile, QueueEvent, Release, RootFolder, SecurityConfig, }; use crate::models::stateful_table::StatefulTable; use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText}; @@ -228,7 +228,10 @@ impl<'a, 'b> Network<'a, 'b> { .get_movie_releases(movie_id) .await .map(RadarrSerdeable::from), - RadarrEvent::GetRootFolders => self.get_root_folders().await.map(RadarrSerdeable::from), + RadarrEvent::GetRootFolders => self + .get_radarr_root_folders() + .await + .map(RadarrSerdeable::from), RadarrEvent::GetSecurityConfig => self .get_radarr_security_config() .await @@ -1785,7 +1788,7 @@ impl<'a, 'b> Network<'a, 'b> { .await } - async fn get_root_folders(&mut self) -> Result> { + async fn get_radarr_root_folders(&mut self) -> Result> { info!("Fetching Radarr root folders"); let event = RadarrEvent::GetRootFolders; diff --git a/src/network/radarr_network_tests.rs b/src/network/radarr_network_tests.rs index e9dcc43..8b83ad5 100644 --- a/src/network/radarr_network_tests.rs +++ b/src/network/radarr_network_tests.rs @@ -2872,7 +2872,7 @@ mod test { } #[tokio::test] - async fn test_handle_get_root_folders_event() { + async fn test_handle_get_radarr_root_folders_event() { let root_folder_json = json!([{ "id": 1, "path": "/nfs", diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index 98b0ccb..a5a1c7b 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -10,7 +10,8 @@ use crate::{ sonarr_data::ActiveSonarrBlock, }, servarr_models::{ - HostConfig, Indexer, LogResponse, QualityProfile, QueueEvent, Release, SecurityConfig, + HostConfig, Indexer, LogResponse, QualityProfile, QueueEvent, Release, RootFolder, + SecurityConfig, }, sonarr_models::{ BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, IndexerSettings, Series, @@ -46,6 +47,7 @@ pub enum SonarrEvent { GetLogs(Option), GetQualityProfiles, GetQueuedEvents, + GetRootFolders, GetEpisodeReleases(Option), GetSeasonReleases(Option<(i64, i64)>), GetSecurityConfig, @@ -71,6 +73,7 @@ impl NetworkResource for SonarrEvent { SonarrEvent::GetLogs(_) => "/log", SonarrEvent::GetQualityProfiles => "/qualityprofile", SonarrEvent::GetQueuedEvents => "/command", + SonarrEvent::GetRootFolders => "/rootfolder", SonarrEvent::GetSeasonReleases(_) | SonarrEvent::GetEpisodeReleases(_) => "/release", SonarrEvent::GetSeriesHistory(_) => "/history/series", SonarrEvent::GetStatus => "/system/status", @@ -147,6 +150,10 @@ impl<'a, 'b> Network<'a, 'b> { .get_queued_sonarr_events() .await .map(SonarrSerdeable::from), + SonarrEvent::GetRootFolders => self + .get_sonarr_root_folders() + .await + .map(SonarrSerdeable::from), SonarrEvent::GetEpisodeReleases(params) => self .get_episode_releases(params) .await @@ -746,6 +753,21 @@ impl<'a, 'b> Network<'a, 'b> { .await } + async fn get_sonarr_root_folders(&mut self) -> Result> { + info!("Fetching Sonarr root folders"); + let event = SonarrEvent::GetRootFolders; + + let request_props = self + .request_props_from(event, RequestMethod::Get, None::<()>, None, None) + .await; + + self + .handle_request::<(), Vec>(request_props, |root_folders, mut app| { + app.data.sonarr_data.root_folders.set_items(root_folders); + }) + .await + } + async fn get_episode_releases(&mut self, episode_id: Option) -> Result> { let event = SonarrEvent::GetEpisodeReleases(None); let id = self.extract_episode_id(episode_id).await; diff --git a/src/network/sonarr_network_tests.rs b/src/network/sonarr_network_tests.rs index b1f7e24..7da3f0a 100644 --- a/src/network/sonarr_network_tests.rs +++ b/src/network/sonarr_network_tests.rs @@ -18,7 +18,7 @@ mod test { use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock; use crate::models::servarr_models::{ HostConfig, Indexer, IndexerField, Language, LogResponse, Quality, QualityProfile, - QualityWrapper, QueueEvent, Release, SecurityConfig, + QualityWrapper, QueueEvent, Release, RootFolder, SecurityConfig, }; use crate::models::sonarr_models::SystemStatus; use crate::models::sonarr_models::{ @@ -172,6 +172,11 @@ mod test { assert_str_eq!(event.resource(), "/queue"); } + #[rstest] + fn test_resource_root_folder(#[values(SonarrEvent::GetRootFolders)] event: SonarrEvent) { + assert_str_eq!(event.resource(), "/rootfolder"); + } + #[rstest] fn test_resource_release( #[values( @@ -2148,6 +2153,41 @@ mod test { } } + #[tokio::test] + async fn test_handle_get_sonarr_root_folders_event() { + let root_folder_json = json!([{ + "id": 1, + "path": "/nfs", + "accessible": true, + "freeSpace": 219902325555200u64, + }]); + let response: Vec = serde_json::from_value(root_folder_json.clone()).unwrap(); + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Get, + None, + Some(root_folder_json), + None, + SonarrEvent::GetRootFolders, + None, + None, + ) + .await; + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + if let SonarrSerdeable::RootFolders(root_folders) = network + .handle_sonarr_event(SonarrEvent::GetRootFolders) + .await + .unwrap() + { + async_server.assert_async().await; + assert_eq!( + app_arc.lock().await.data.sonarr_data.root_folders.items, + vec![root_folder()] + ); + assert_eq!(root_folders, response); + } + } + #[tokio::test] async fn test_handle_get_episode_releases_event() { let release_json = json!([{ @@ -3839,4 +3879,14 @@ mod test { quality: quality_wrapper(), } } + + fn root_folder() -> RootFolder { + RootFolder { + id: 1, + path: "/nfs".to_owned(), + accessible: true, + free_space: 219902325555200, + unmapped_folders: None, + } + } } diff --git a/src/ui/radarr_ui/mod.rs b/src/ui/radarr_ui/mod.rs index 8f58912..ddc2422 100644 --- a/src/ui/radarr_ui/mod.rs +++ b/src/ui/radarr_ui/mod.rs @@ -9,8 +9,9 @@ use ratatui::Frame; use crate::app::App; use crate::logos::RADARR_LOGO; -use crate::models::radarr_models::{DiskSpace, DownloadRecord, Movie, RootFolder}; +use crate::models::radarr_models::{DiskSpace, DownloadRecord, Movie}; use crate::models::servarr_data::radarr::radarr_data::RadarrData; +use crate::models::servarr_models::RootFolder; use crate::models::Route; use crate::ui::draw_tabs; use crate::ui::radarr_ui::blocklist::BlocklistUi; diff --git a/src/ui/radarr_ui/root_folders/mod.rs b/src/ui/radarr_ui/root_folders/mod.rs index bff2797..381b37c 100644 --- a/src/ui/radarr_ui/root_folders/mod.rs +++ b/src/ui/radarr_ui/root_folders/mod.rs @@ -3,8 +3,8 @@ use ratatui::widgets::{Cell, Row}; use ratatui::Frame; use crate::app::App; -use crate::models::radarr_models::RootFolder; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ROOT_FOLDERS_BLOCKS}; +use crate::models::servarr_models::RootFolder; use crate::models::Route; use crate::ui::styles::ManagarrStyle; use crate::ui::utils::layout_block_top_border;