diff --git a/src/cli/radarr/mod.rs b/src/cli/radarr/mod.rs index cd64155..623dd5a 100644 --- a/src/cli/radarr/mod.rs +++ b/src/cli/radarr/mod.rs @@ -12,7 +12,7 @@ use tokio::sync::Mutex; use crate::app::App; use crate::cli::CliCommandHandler; -use crate::models::radarr_models::{ReleaseDownloadBody, TaskName}; +use crate::models::radarr_models::{RadarrTaskName, ReleaseDownloadBody}; use crate::network::radarr_network::RadarrEvent; use crate::network::NetworkTrait; use anyhow::Result; @@ -107,7 +107,7 @@ pub enum RadarrCommand { value_enum, required = true )] - task_name: TaskName, + task_name: RadarrTaskName, }, #[command( about = "Test the indexer with the given ID. Note that a successful test returns an empty JSON body; i.e. '{}'" diff --git a/src/cli/radarr/radarr_command_tests.rs b/src/cli/radarr/radarr_command_tests.rs index 88bf862..fcb59d2 100644 --- a/src/cli/radarr/radarr_command_tests.rs +++ b/src/cli/radarr/radarr_command_tests.rs @@ -261,8 +261,8 @@ mod tests { }, models::{ radarr_models::{ - BlocklistItem, BlocklistResponse, IndexerSettings, RadarrSerdeable, ReleaseDownloadBody, - TaskName, + BlocklistItem, BlocklistResponse, IndexerSettings, RadarrSerdeable, RadarrTaskName, + ReleaseDownloadBody, }, Serdeable, }, @@ -389,7 +389,7 @@ mod tests { #[tokio::test] async fn test_start_task_command() { - let expected_task_name = TaskName::ApplicationCheckUpdate; + let expected_task_name = RadarrTaskName::ApplicationCheckUpdate; let mut mock_network = MockNetworkTrait::new(); mock_network .expect_handle_network_event() @@ -404,7 +404,7 @@ mod tests { }); let app_arc = Arc::new(Mutex::new(App::default())); let start_task_command = RadarrCommand::StartTask { - task_name: TaskName::ApplicationCheckUpdate, + task_name: RadarrTaskName::ApplicationCheckUpdate, }; let result = RadarrCliHandler::with(&app_arc, start_task_command, &mut mock_network) diff --git a/src/handlers/radarr_handlers/system/system_details_handler_tests.rs b/src/handlers/radarr_handlers/system/system_details_handler_tests.rs index cde9d2f..65c9497 100644 --- a/src/handlers/radarr_handlers/system/system_details_handler_tests.rs +++ b/src/handlers/radarr_handlers/system/system_details_handler_tests.rs @@ -8,7 +8,7 @@ mod tests { use crate::event::Key; use crate::handlers::radarr_handlers::system::system_details_handler::SystemDetailsHandler; use crate::handlers::KeyEventHandler; - use crate::models::radarr_models::Task; + use crate::models::radarr_models::RadarrTask; use crate::models::servarr_data::radarr::radarr_data::{ ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS, }; @@ -74,7 +74,7 @@ mod tests { .data .radarr_data .tasks - .set_items(simple_stateful_iterable_vec!(Task, String, name)); + .set_items(simple_stateful_iterable_vec!(RadarrTask, String, name)); SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle(); @@ -102,7 +102,7 @@ mod tests { .data .radarr_data .tasks - .set_items(simple_stateful_iterable_vec!(Task, String, name)); + .set_items(simple_stateful_iterable_vec!(RadarrTask, String, name)); SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle(); @@ -318,7 +318,7 @@ mod tests { .data .radarr_data .tasks - .set_items(extended_stateful_iterable_vec!(Task, String, name)); + .set_items(extended_stateful_iterable_vec!(RadarrTask, String, name)); SystemDetailsHandler::with( &DEFAULT_KEYBINDINGS.end.key, @@ -357,7 +357,7 @@ mod tests { .data .radarr_data .tasks - .set_items(extended_stateful_iterable_vec!(Task, String, name)); + .set_items(extended_stateful_iterable_vec!(RadarrTask, String, name)); SystemDetailsHandler::with( &DEFAULT_KEYBINDINGS.end.key, @@ -789,7 +789,11 @@ mod tests { app.is_loading = is_ready; app.push_navigation_stack(ActiveRadarrBlock::System.into()); app.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into()); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemDetailsHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::SystemTasks, &None) .handle(); diff --git a/src/handlers/radarr_handlers/system/system_handler_tests.rs b/src/handlers/radarr_handlers/system/system_handler_tests.rs index b1c864a..03b3aec 100644 --- a/src/handlers/radarr_handlers/system/system_handler_tests.rs +++ b/src/handlers/radarr_handlers/system/system_handler_tests.rs @@ -9,7 +9,7 @@ mod tests { use crate::event::Key; use crate::handlers::radarr_handlers::system::SystemHandler; use crate::handlers::KeyEventHandler; - use crate::models::radarr_models::Task; + use crate::models::radarr_models::RadarrTask; use crate::models::servarr_data::radarr::radarr_data::{ ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS, }; @@ -105,7 +105,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.update.key, @@ -135,7 +139,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.update.key, @@ -160,7 +168,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.events.key, @@ -190,7 +202,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.events.key, @@ -215,7 +231,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); app.push_navigation_stack(ActiveRadarrBlock::System.into()); SystemHandler::with( @@ -244,7 +264,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); app.push_navigation_stack(ActiveRadarrBlock::System.into()); SystemHandler::with( @@ -271,7 +295,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.logs.key, @@ -309,7 +337,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.logs.key, @@ -335,7 +367,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.tasks.key, @@ -365,7 +401,11 @@ mod tests { .radarr_data .queued_events .set_items(vec![QueueEvent::default()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); SystemHandler::with( &DEFAULT_KEYBINDINGS.tasks.key, @@ -430,7 +470,11 @@ mod tests { fn test_system_handler_is_not_ready_when_logs_is_empty() { let mut app = App::default(); app.is_loading = false; - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); app .data .radarr_data @@ -473,7 +517,11 @@ mod tests { let mut app = App::default(); app.is_loading = false; app.data.radarr_data.logs.set_items(vec!["test".into()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); let system_handler = SystemHandler::with( &DEFAULT_KEYBINDINGS.update.key, @@ -490,7 +538,11 @@ mod tests { let mut app = App::default(); app.is_loading = false; app.data.radarr_data.logs.set_items(vec!["test".into()]); - app.data.radarr_data.tasks.set_items(vec![Task::default()]); + app + .data + .radarr_data + .tasks + .set_items(vec![RadarrTask::default()]); app .data .radarr_data diff --git a/src/models/radarr_models.rs b/src/models/radarr_models.rs index 981f69c..ecb7b16 100644 --- a/src/models/radarr_models.rs +++ b/src/models/radarr_models.rs @@ -435,9 +435,9 @@ pub struct SystemStatus { #[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] -pub struct Task { +pub struct RadarrTask { pub name: String, - pub task_name: TaskName, + pub task_name: RadarrTaskName, #[serde(deserialize_with = "super::from_i64")] pub interval: i64, pub last_execution: DateTime, @@ -447,7 +447,7 @@ pub struct Task { #[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Copy, ValueEnum)] #[serde(rename_all = "PascalCase")] -pub enum TaskName { +pub enum RadarrTaskName { #[default] ApplicationCheckUpdate, Backup, @@ -462,7 +462,7 @@ pub enum TaskName { RssSync, } -impl Display for TaskName { +impl Display for RadarrTaskName { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let task_name = serde_json::to_string(&self) .expect("Unable to serialize task name") @@ -514,7 +514,7 @@ pub enum RadarrSerdeable { SecurityConfig(SecurityConfig), SystemStatus(SystemStatus), Tags(Vec), - Tasks(Vec), + Tasks(Vec), Updates(Vec), AddMovieSearchResults(Vec), IndexerTestResults(Vec), @@ -555,7 +555,7 @@ serde_enum_from!( SecurityConfig(SecurityConfig), SystemStatus(SystemStatus), Tags(Vec), - Tasks(Vec), + Tasks(Vec), Updates(Vec), AddMovieSearchResults(Vec), IndexerTestResults(Vec), diff --git a/src/models/radarr_models_tests.rs b/src/models/radarr_models_tests.rs index eb07c6b..4afe5a1 100644 --- a/src/models/radarr_models_tests.rs +++ b/src/models/radarr_models_tests.rs @@ -8,7 +8,7 @@ mod tests { AddMovieSearchResult, BlocklistItem, BlocklistResponse, Collection, Credit, DiskSpace, DownloadRecord, DownloadsResponse, Indexer, IndexerSettings, IndexerTestResult, MinimumAvailability, Monitor, Movie, MovieHistoryItem, QualityProfile, RadarrSerdeable, - Release, SystemStatus, Tag, Task, TaskName, Update, + RadarrTask, RadarrTaskName, Release, SystemStatus, Tag, Update, }, servarr_models::{HostConfig, Log, LogResponse, QueueEvent, RootFolder, SecurityConfig}, EnumDisplayStyle, Serdeable, @@ -17,7 +17,7 @@ mod tests { #[test] fn test_task_name_display() { assert_str_eq!( - TaskName::ApplicationCheckUpdate.to_string(), + RadarrTaskName::ApplicationCheckUpdate.to_string(), "ApplicationCheckUpdate" ); } @@ -383,9 +383,9 @@ mod tests { #[test] fn test_radarr_serdeable_from_tasks() { - let tasks = vec![Task { + let tasks = vec![RadarrTask { name: "test".to_owned(), - ..Task::default() + ..RadarrTask::default() }]; let radarr_serdeable: RadarrSerdeable = tasks.clone().into(); diff --git a/src/models/servarr_data/radarr/radarr_data.rs b/src/models/servarr_data/radarr/radarr_data.rs index 1e2ada9..483a1a0 100644 --- a/src/models/servarr_data/radarr/radarr_data.rs +++ b/src/models/servarr_data/radarr/radarr_data.rs @@ -7,7 +7,7 @@ use crate::app::radarr::radarr_context_clues::{ }; use crate::models::radarr_models::{ AddMovieSearchResult, BlocklistItem, Collection, CollectionMovie, DownloadRecord, - IndexerSettings, Movie, Task, + IndexerSettings, Movie, RadarrTask, }; use crate::models::servarr_data::radarr::modals::{ AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, IndexerTestResultModalItem, @@ -48,7 +48,7 @@ pub struct RadarrData<'a> { pub collection_movies: StatefulTable, pub logs: StatefulList, pub log_details: StatefulList, - pub tasks: StatefulTable, + pub tasks: StatefulTable, pub queued_events: StatefulTable, pub updates: ScrollableText, pub main_tabs: TabState, diff --git a/src/models/servarr_data/sonarr/sonarr_data.rs b/src/models/servarr_data/sonarr/sonarr_data.rs index 532b969..db5461f 100644 --- a/src/models/servarr_data/sonarr/sonarr_data.rs +++ b/src/models/servarr_data/sonarr/sonarr_data.rs @@ -5,7 +5,7 @@ use strum::EnumIter; use crate::models::{ servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder}, sonarr_models::{ - BlocklistItem, DownloadRecord, IndexerSettings, Season, Series, SonarrHistoryItem, + BlocklistItem, DownloadRecord, IndexerSettings, Season, Series, SonarrHistoryItem, SonarrTask, }, stateful_list::StatefulList, stateful_table::StatefulTable, @@ -36,6 +36,7 @@ pub struct SonarrData { pub series_history: Option>, pub start_time: DateTime, pub tags_map: BiMap, + pub tasks: StatefulTable, pub version: String, } @@ -59,6 +60,7 @@ impl Default for SonarrData { series_history: None, start_time: DateTime::default(), tags_map: BiMap::default(), + tasks: StatefulTable::default(), version: String::new(), } } diff --git a/src/models/servarr_data/sonarr/sonarr_data_tests.rs b/src/models/servarr_data/sonarr/sonarr_data_tests.rs index 8fc8cc5..495a5af 100644 --- a/src/models/servarr_data/sonarr/sonarr_data_tests.rs +++ b/src/models/servarr_data/sonarr/sonarr_data_tests.rs @@ -51,6 +51,7 @@ mod tests { assert!(sonarr_data.series_history.is_none()); assert_eq!(sonarr_data.start_time, >::default()); assert!(sonarr_data.tags_map.is_empty()); + assert!(sonarr_data.tasks.is_empty()); assert!(sonarr_data.version.is_empty()); } } diff --git a/src/models/sonarr_models.rs b/src/models/sonarr_models.rs index 4a8ea3e..e5ad2a6 100644 --- a/src/models/sonarr_models.rs +++ b/src/models/sonarr_models.rs @@ -388,6 +388,44 @@ pub struct SonarrHistoryItem { pub data: SonarrHistoryData, } +#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct SonarrTask { + pub name: String, + pub task_name: SonarrTaskName, + #[serde(deserialize_with = "super::from_i64")] + pub interval: i64, + pub last_execution: DateTime, + pub last_duration: String, + pub next_execution: DateTime, +} + +#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Copy, ValueEnum)] +#[serde(rename_all = "PascalCase")] +pub enum SonarrTaskName { + #[default] + ApplicationUpdateCheck, + Backup, + CheckHealth, + CleanUpRecycleBin, + Housekeeping, + ImportListSync, + MessagingCleanup, + RefreshMonitoredDownloads, + RefreshSeries, + RssSync, + UpdateSceneMapping, +} + +impl Display for SonarrTaskName { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let task_name = serde_json::to_string(&self) + .expect("Unable to serialize task name") + .replace('"', ""); + write!(f, "{task_name}") + } +} + #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)] #[serde(untagged)] #[allow(clippy::large_enum_variant)] @@ -412,6 +450,7 @@ pub enum SonarrSerdeable { SystemStatus(SystemStatus), Tag(Tag), Tags(Vec), + Tasks(Vec), BlocklistResponse(BlocklistResponse), LogResponse(LogResponse), } @@ -450,6 +489,7 @@ serde_enum_from!( SystemStatus(SystemStatus), Tag(Tag), Tags(Vec), + Tasks(Vec), BlocklistResponse(BlocklistResponse), LogResponse(LogResponse), } diff --git a/src/models/sonarr_models_tests.rs b/src/models/sonarr_models_tests.rs index 44f9446..abf970a 100644 --- a/src/models/sonarr_models_tests.rs +++ b/src/models/sonarr_models_tests.rs @@ -11,7 +11,7 @@ mod tests { sonarr_models::{ BlocklistItem, BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, IndexerSettings, Series, SeriesStatus, SeriesType, SonarrHistoryEventType, SonarrHistoryItem, - SonarrSerdeable, SystemStatus, + SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus, }, EnumDisplayStyle, Serdeable, }; @@ -117,6 +117,14 @@ mod tests { ); } + #[test] + fn test_task_name_display() { + assert_str_eq!( + SonarrTaskName::ApplicationUpdateCheck.to_string(), + "ApplicationUpdateCheck" + ); + } + #[test] fn test_sonarr_serdeable_from() { let sonarr_serdeable = SonarrSerdeable::Value(json!({})); @@ -406,4 +414,16 @@ mod tests { assert_eq!(sonarr_serdeable, SonarrSerdeable::Tags(tags)); } + + #[test] + fn test_sonarr_serdeable_from_tasks() { + let tasks = vec![SonarrTask { + name: "test".to_owned(), + ..SonarrTask::default() + }]; + + let sonarr_serdeable: SonarrSerdeable = tasks.clone().into(); + + assert_eq!(sonarr_serdeable, SonarrSerdeable::Tasks(tasks)); + } } diff --git a/src/network/radarr_network.rs b/src/network/radarr_network.rs index 1f70e65..88bf9ea 100644 --- a/src/network/radarr_network.rs +++ b/src/network/radarr_network.rs @@ -10,8 +10,8 @@ use crate::models::radarr_models::{ AddMovieBody, AddMovieSearchResult, AddOptions, BlocklistResponse, Collection, CollectionMovie, CommandBody, Credit, CreditType, DeleteMovieParams, DownloadRecord, DownloadsResponse, EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings, IndexerTestResult, - Movie, MovieCommandBody, MovieHistoryItem, RadarrSerdeable, ReleaseDownloadBody, SystemStatus, - Task, TaskName, Update, + Movie, MovieCommandBody, MovieHistoryItem, RadarrSerdeable, RadarrTask, RadarrTaskName, + ReleaseDownloadBody, SystemStatus, Update, }; use crate::models::servarr_data::radarr::modals::{ AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, IndexerTestResultModalItem, @@ -73,7 +73,7 @@ pub enum RadarrEvent { GetUpdates, HealthCheck, SearchNewMovie(Option), - StartTask(Option), + StartTask(Option), TestIndexer(Option), TestAllIndexers, TriggerAutomaticSearch(Option), @@ -243,7 +243,7 @@ impl<'a, 'b> Network<'a, 'b> { .map(RadarrSerdeable::from), RadarrEvent::GetStatus => self.get_radarr_status().await.map(RadarrSerdeable::from), RadarrEvent::GetTags => self.get_radarr_tags().await.map(RadarrSerdeable::from), - RadarrEvent::GetTasks => self.get_tasks().await.map(RadarrSerdeable::from), + RadarrEvent::GetTasks => self.get_radarr_tasks().await.map(RadarrSerdeable::from), RadarrEvent::GetUpdates => self.get_updates().await.map(RadarrSerdeable::from), RadarrEvent::HealthCheck => self .get_radarr_healthcheck() @@ -1855,7 +1855,7 @@ impl<'a, 'b> Network<'a, 'b> { .await } - async fn get_tasks(&mut self) -> Result> { + async fn get_radarr_tasks(&mut self) -> Result> { info!("Fetching Radarr tasks"); let event = RadarrEvent::GetTasks; @@ -1864,7 +1864,7 @@ impl<'a, 'b> Network<'a, 'b> { .await; self - .handle_request::<(), Vec>(request_props, |tasks_vec, mut app| { + .handle_request::<(), Vec>(request_props, |tasks_vec, mut app| { app.data.radarr_data.tasks.set_items(tasks_vec); }) .await @@ -2006,7 +2006,7 @@ impl<'a, 'b> Network<'a, 'b> { } } - async fn start_task(&mut self, task: Option) -> Result { + async fn start_task(&mut self, task: Option) -> Result { let event = RadarrEvent::StartTask(None); let task_name = if let Some(t_name) = task { t_name diff --git a/src/network/radarr_network_tests.rs b/src/network/radarr_network_tests.rs index a36c4dc..c4cc9f6 100644 --- a/src/network/radarr_network_tests.rs +++ b/src/network/radarr_network_tests.rs @@ -733,9 +733,9 @@ mod test { .data .radarr_data .tasks - .set_items(vec![Task { - task_name: TaskName::default(), - ..Task::default() + .set_items(vec![RadarrTask { + task_name: RadarrTaskName::default(), + ..RadarrTask::default() }]); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); @@ -767,7 +767,7 @@ mod test { let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); if let RadarrSerdeable::Value(value) = network - .handle_radarr_event(RadarrEvent::StartTask(Some(TaskName::default()))) + .handle_radarr_event(RadarrEvent::StartTask(Some(RadarrTaskName::default()))) .await .unwrap() { @@ -2666,7 +2666,7 @@ mod test { } #[tokio::test] - async fn test_handle_get_tasks_event() { + async fn test_handle_get_radarr_tasks_event() { let tasks_json = json!([{ "name": "Application Check Update", "taskName": "ApplicationCheckUpdate", @@ -2683,20 +2683,20 @@ mod test { "nextExecution": "2023-05-20T21:29:16Z", "lastDuration": "00:00:00.5111547", }]); - let response: Vec = serde_json::from_value(tasks_json.clone()).unwrap(); + let response: Vec = serde_json::from_value(tasks_json.clone()).unwrap(); let timestamp = DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap()); let expected_tasks = vec![ - Task { + RadarrTask { name: "Application Check Update".to_owned(), - task_name: TaskName::ApplicationCheckUpdate, + task_name: RadarrTaskName::ApplicationCheckUpdate, interval: 360, last_execution: timestamp, next_execution: timestamp, last_duration: "00:00:00.5111547".to_owned(), }, - Task { + RadarrTask { name: "Backup".to_owned(), - task_name: TaskName::Backup, + task_name: RadarrTaskName::Backup, interval: 10080, last_execution: timestamp, next_execution: timestamp, diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index 557ddab..f8029ff 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -15,7 +15,7 @@ use crate::{ }, sonarr_models::{ BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, IndexerSettings, Series, - SonarrHistoryItem, SonarrHistoryWrapper, SonarrSerdeable, SystemStatus, + SonarrHistoryItem, SonarrHistoryWrapper, SonarrSerdeable, SonarrTask, SystemStatus, }, stateful_table::StatefulTable, HorizontallyScrollableText, Route, Scrollable, ScrollableText, @@ -60,6 +60,7 @@ pub enum SonarrEvent { GetSeriesHistory(Option), GetStatus, GetTags, + GetTasks, HealthCheck, ListSeries, MarkHistoryItemAsFailed(i64), @@ -88,6 +89,7 @@ impl NetworkResource for SonarrEvent { SonarrEvent::GetSeasonReleases(_) | SonarrEvent::GetEpisodeReleases(_) => "/release", SonarrEvent::GetSeriesHistory(_) => "/history/series", SonarrEvent::GetStatus => "/system/status", + SonarrEvent::GetTasks => "/system/task", SonarrEvent::HealthCheck => "/health", SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) => "/series", SonarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed", @@ -202,6 +204,7 @@ impl<'a, 'b> Network<'a, 'b> { .map(SonarrSerdeable::from), SonarrEvent::GetStatus => self.get_sonarr_status().await.map(SonarrSerdeable::from), SonarrEvent::GetTags => self.get_sonarr_tags().await.map(SonarrSerdeable::from), + SonarrEvent::GetTasks => self.get_sonarr_tasks().await.map(SonarrSerdeable::from), SonarrEvent::HealthCheck => self .get_sonarr_healthcheck() .await @@ -1156,6 +1159,21 @@ impl<'a, 'b> Network<'a, 'b> { .await } + async fn get_sonarr_tasks(&mut self) -> Result> { + info!("Fetching Sonarr tasks"); + let event = SonarrEvent::GetTasks; + + let request_props = self + .request_props_from(event, RequestMethod::Get, None::<()>, None, None) + .await; + + self + .handle_request::<(), Vec>(request_props, |tasks_vec, mut app| { + app.data.sonarr_data.tasks.set_items(tasks_vec); + }) + .await + } + async fn mark_sonarr_history_item_as_failed(&mut self, history_item_id: i64) -> Result { info!("Marking the Sonarr history item with ID: {history_item_id} as 'failed'"); let event = SonarrEvent::MarkHistoryItemAsFailed(history_item_id); diff --git a/src/network/sonarr_network_tests.rs b/src/network/sonarr_network_tests.rs index 343ec2d..9eddb75 100644 --- a/src/network/sonarr_network_tests.rs +++ b/src/network/sonarr_network_tests.rs @@ -20,13 +20,14 @@ mod test { DiskSpace, HostConfig, Indexer, IndexerField, Language, LogResponse, Quality, QualityProfile, QualityWrapper, QueueEvent, Release, RootFolder, SecurityConfig, Tag, }; - use crate::models::sonarr_models::SystemStatus; use crate::models::sonarr_models::{ BlocklistItem, DownloadRecord, DownloadsResponse, Episode, EpisodeFile, MediaInfo, + SonarrTaskName, }; use crate::models::sonarr_models::{ BlocklistResponse, SonarrHistoryData, SonarrHistoryItem, SonarrHistoryWrapper, }; + use crate::models::sonarr_models::{SonarrTask, SystemStatus}; use crate::models::stateful_table::StatefulTable; use crate::models::HorizontallyScrollableText; use crate::models::{sonarr_models::SonarrSerdeable, stateful_table::SortOption}; @@ -217,6 +218,7 @@ mod test { #[case(SonarrEvent::GetLogs(Some(500)), "/log")] #[case(SonarrEvent::GetQualityProfiles, "/qualityprofile")] #[case(SonarrEvent::GetStatus, "/system/status")] + #[case(SonarrEvent::GetTasks, "/system/task")] #[case(SonarrEvent::MarkHistoryItemAsFailed(0), "/history/failed")] fn test_resource(#[case] event: SonarrEvent, #[case] expected_uri: String) { assert_str_eq!(event.resource(), expected_uri); @@ -3675,6 +3677,70 @@ mod test { } } + #[tokio::test] + async fn test_handle_get_sonarr_tasks_event() { + let tasks_json = json!([{ + "name": "Application Update Check", + "taskName": "ApplicationUpdateCheck", + "interval": 360, + "lastExecution": "2023-05-20T21:29:16Z", + "nextExecution": "2023-05-20T21:29:16Z", + "lastDuration": "00:00:00.5111547", + }, + { + "name": "Backup", + "taskName": "Backup", + "interval": 10080, + "lastExecution": "2023-05-20T21:29:16Z", + "nextExecution": "2023-05-20T21:29:16Z", + "lastDuration": "00:00:00.5111547", + }]); + let response: Vec = serde_json::from_value(tasks_json.clone()).unwrap(); + let timestamp = DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap()); + let expected_tasks = vec![ + SonarrTask { + name: "Application Update Check".to_owned(), + task_name: SonarrTaskName::ApplicationUpdateCheck, + interval: 360, + last_execution: timestamp, + next_execution: timestamp, + last_duration: "00:00:00.5111547".to_owned(), + }, + SonarrTask { + name: "Backup".to_owned(), + task_name: SonarrTaskName::Backup, + interval: 10080, + last_execution: timestamp, + next_execution: timestamp, + last_duration: "00:00:00.5111547".to_owned(), + }, + ]; + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Get, + None, + Some(tasks_json), + None, + SonarrEvent::GetTasks, + None, + None, + ) + .await; + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + if let SonarrSerdeable::Tasks(tasks) = network + .handle_sonarr_event(SonarrEvent::GetTasks) + .await + .unwrap() + { + async_server.assert_async().await; + assert_eq!( + app_arc.lock().await.data.sonarr_data.tasks.items, + expected_tasks + ); + assert_eq!(tasks, response); + } + } + #[tokio::test] async fn test_handle_mark_sonarr_history_item_as_failed_event() { let expected_history_item_id = 1; diff --git a/src/ui/radarr_ui/system/mod.rs b/src/ui/radarr_ui/system/mod.rs index 5616649..c46653e 100644 --- a/src/ui/radarr_ui/system/mod.rs +++ b/src/ui/radarr_ui/system/mod.rs @@ -12,7 +12,7 @@ use ratatui::{ }; use crate::app::App; -use crate::models::radarr_models::Task; +use crate::models::radarr_models::RadarrTask; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_models::QueueEvent; use crate::ui::radarr_ui::radarr_ui_utils::{convert_to_minutes_hours_days, style_log_list_item}; @@ -91,7 +91,7 @@ pub(super) fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area: } fn draw_tasks(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { - let tasks_row_mapping = |task: &Task| { + let tasks_row_mapping = |task: &RadarrTask| { let task_props = extract_task_props(task); Row::new(vec![ @@ -218,7 +218,7 @@ pub(super) struct TaskProps { pub(super) next_execution: String, } -pub(super) fn extract_task_props(task: &Task) -> TaskProps { +pub(super) fn extract_task_props(task: &RadarrTask) -> TaskProps { let interval = convert_to_minutes_hours_days(task.interval); let last_duration = &task.last_duration[..8]; let next_execution = diff --git a/src/ui/radarr_ui/system/system_details_ui.rs b/src/ui/radarr_ui/system/system_details_ui.rs index db4582a..cfc3c5c 100644 --- a/src/ui/radarr_ui/system/system_details_ui.rs +++ b/src/ui/radarr_ui/system/system_details_ui.rs @@ -6,7 +6,7 @@ use ratatui::Frame; use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES}; use crate::app::radarr::radarr_context_clues::SYSTEM_TASKS_CONTEXT_CLUES; use crate::app::App; -use crate::models::radarr_models::Task; +use crate::models::radarr_models::RadarrTask; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS}; use crate::models::Route; use crate::ui::radarr_ui::radarr_ui_utils::style_log_list_item; @@ -108,7 +108,7 @@ fn draw_logs_popup(f: &mut Frame<'_>, app: &mut App<'_>) { fn draw_tasks_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { let help_footer = Some(build_context_clue_string(&SYSTEM_TASKS_CONTEXT_CLUES)); - let tasks_row_mapping = |task: &Task| { + let tasks_row_mapping = |task: &RadarrTask| { let task_props = extract_task_props(task); Row::new(vec![