diff --git a/src/cli/sonarr/list_command_handler.rs b/src/cli/sonarr/list_command_handler.rs index cf92a36..7bc46ff 100644 --- a/src/cli/sonarr/list_command_handler.rs +++ b/src/cli/sonarr/list_command_handler.rs @@ -67,6 +67,23 @@ pub enum SonarrListCommand { QueuedEvents, #[command(about = "List all root folders in Sonarr")] RootFolders, + #[command( + about = "Fetch all history events for the given season corresponding to the series with the given ID." + )] + SeasonHistory { + #[arg( + long, + help = "The Sonarr ID of the series whose history you wish to fetch and list", + required = true + )] + series_id: i64, + #[arg( + long, + help = "The season number to fetch history events for", + required = true + )] + season_number: i64, + }, #[command(about = "List all series in your Sonarr library")] Series, #[command(about = "Fetch all history events for the series with the given ID")] @@ -207,6 +224,18 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrListCommand> for SonarrListCommandH .await?; serde_json::to_string_pretty(&resp)? } + SonarrListCommand::SeasonHistory { + series_id, + season_number, + } => { + let resp = self + .network + .handle_network_event( + SonarrEvent::GetSeasonHistory(Some((series_id, season_number))).into(), + ) + .await?; + serde_json::to_string_pretty(&resp)? + } SonarrListCommand::Series => { let resp = self .network diff --git a/src/cli/sonarr/list_command_handler_tests.rs b/src/cli/sonarr/list_command_handler_tests.rs index 7e71599..54cc3b0 100644 --- a/src/cli/sonarr/list_command_handler_tests.rs +++ b/src/cli/sonarr/list_command_handler_tests.rs @@ -149,6 +149,58 @@ mod tests { } } + #[test] + fn test_season_history_requires_series_id() { + let result = Cli::command().try_get_matches_from([ + "managarr", + "sonarr", + "list", + "season-history", + "--season-number", + "1", + ]); + + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().kind(), + ErrorKind::MissingRequiredArgument + ); + } + + #[test] + fn test_season_history_requires_season_number() { + let result = Cli::command().try_get_matches_from([ + "managarr", + "sonarr", + "list", + "season-history", + "--series-id", + "1", + ]); + + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().kind(), + ErrorKind::MissingRequiredArgument + ); + } + + #[test] + fn test_season_history_requirements_satisfied() { + let result = Cli::command().try_get_matches_from([ + "managarr", + "sonarr", + "list", + "season-history", + "--series-id", + "1", + "--season-number", + "1", + ]); + + assert!(result.is_ok()); + } + #[test] fn test_list_series_history_requires_series_id() { let result = @@ -368,5 +420,35 @@ mod tests { assert!(result.is_ok()); } + + #[tokio::test] + async fn test_list_season_history_command() { + let expected_series_id = 1; + let expected_season_number = 1; + let mut mock_network = MockNetworkTrait::new(); + mock_network + .expect_handle_network_event() + .with(eq::( + SonarrEvent::GetSeasonHistory(Some((expected_series_id, expected_season_number))).into(), + )) + .times(1) + .returning(|_| { + Ok(Serdeable::Sonarr(SonarrSerdeable::Value( + json!({"testResponse": "response"}), + ))) + }); + let app_arc = Arc::new(Mutex::new(App::default())); + let list_season_history_command = SonarrListCommand::SeasonHistory { + series_id: 1, + season_number: 1, + }; + + let result = + SonarrListCommandHandler::with(&app_arc, list_season_history_command, &mut mock_network) + .handle() + .await; + + assert!(result.is_ok()); + } } } diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index 7cc85dc..a782071 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -1895,7 +1895,7 @@ impl<'a, 'b> Network<'a, 'b> { async fn get_sonarr_season_history( &mut self, series_season_id_tuple: Option<(i64, i64)>, - ) -> Result { + ) -> Result> { let event = SonarrEvent::GetSeasonHistory(None); let (series_id, season_number) = if let Some((series_id, season_number)) = series_season_id_tuple { @@ -1915,12 +1915,12 @@ impl<'a, 'b> Network<'a, 'b> { .await; self - .handle_request::<(), SonarrHistoryWrapper>(request_props, |history_response, mut app| { + .handle_request::<(), Vec>(request_props, |history_items, mut app| { if app.data.sonarr_data.season_details_modal.is_none() { app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default()); } - let mut history_vec = history_response.records; + let mut history_vec = history_items; history_vec.sort_by(|a, b| a.id.cmp(&b.id)); app .data diff --git a/src/network/sonarr_network_tests.rs b/src/network/sonarr_network_tests.rs index be959fb..dd1e27b 100644 --- a/src/network/sonarr_network_tests.rs +++ b/src/network/sonarr_network_tests.rs @@ -4168,7 +4168,7 @@ mod test { #[tokio::test] async fn test_handle_get_sonarr_season_history_event() { - let history_json = json!({"records": [{ + let history_json = json!([{ "id": 123, "sourceTitle": "z episode", "episodeId": 1007, @@ -4193,8 +4193,8 @@ mod test { "droppedPath": "/nfs/nzbget/completed/series/Coolness/something.cool.mkv", "importedPath": "/nfs/tv/Coolness/Season 1/Coolness - S01E01 - Something Cool Bluray-1080p.mkv" } - }]}); - let response: SonarrHistoryWrapper = serde_json::from_value(history_json.clone()).unwrap(); + }]); + let response: Vec = serde_json::from_value(history_json.clone()).unwrap(); let expected_history_items = vec![ SonarrHistoryItem { id: 123, @@ -4247,7 +4247,7 @@ mod test { .sort_asc = true; let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); - if let SonarrSerdeable::SonarrHistoryWrapper(history) = network + if let SonarrSerdeable::SonarrHistoryItems(history) = network .handle_sonarr_event(SonarrEvent::GetSeasonHistory(None)) .await .unwrap() @@ -4284,7 +4284,7 @@ mod test { #[tokio::test] async fn test_handle_get_sonarr_season_history_event_uses_provided_series_id_and_season_number() { - let history_json = json!({"records": [{ + let history_json = json!([{ "id": 123, "sourceTitle": "z episode", "episodeId": 1007, @@ -4309,8 +4309,8 @@ mod test { "droppedPath": "/nfs/nzbget/completed/series/Coolness/something.cool.mkv", "importedPath": "/nfs/tv/Coolness/Season 1/Coolness - S01E01 - Something Cool Bluray-1080p.mkv" } - }]}); - let response: SonarrHistoryWrapper = serde_json::from_value(history_json.clone()).unwrap(); + }]); + let response: Vec = serde_json::from_value(history_json.clone()).unwrap(); let expected_history_items = vec![ SonarrHistoryItem { id: 123, @@ -4363,7 +4363,7 @@ mod test { .sort_asc = true; let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); - if let SonarrSerdeable::SonarrHistoryWrapper(history) = network + if let SonarrSerdeable::SonarrHistoryItems(history) = network .handle_sonarr_event(SonarrEvent::GetSeasonHistory(Some((2, 2)))) .await .unwrap() @@ -4400,7 +4400,7 @@ mod test { #[tokio::test] async fn test_handle_get_sonarr_season_history_event_empty_season_details_modal() { - let history_json = json!({"records": [{ + let history_json = json!([{ "id": 123, "sourceTitle": "z episode", "episodeId": 1007, @@ -4425,8 +4425,8 @@ mod test { "droppedPath": "/nfs/nzbget/completed/series/Coolness/something.cool.mkv", "importedPath": "/nfs/tv/Coolness/Season 1/Coolness - S01E01 - Something Cool Bluray-1080p.mkv" } - }]}); - let response: SonarrHistoryWrapper = serde_json::from_value(history_json.clone()).unwrap(); + }]); + let response: Vec = serde_json::from_value(history_json.clone()).unwrap(); let expected_history_items = vec![ SonarrHistoryItem { id: 123, @@ -4467,7 +4467,7 @@ mod test { .set_items(vec![season()]); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); - if let SonarrSerdeable::SonarrHistoryWrapper(history) = network + if let SonarrSerdeable::SonarrHistoryItems(history) = network .handle_sonarr_event(SonarrEvent::GetSeasonHistory(None)) .await .unwrap()