feat(network): Support for fetching Sonarr updates

This commit is contained in:
2024-11-22 16:46:36 -07:00
parent 22fbe025d9
commit 16ca8841a1
10 changed files with 230 additions and 36 deletions
+4 -4
View File
@@ -11,7 +11,7 @@ use crate::models::radarr_models::{
CommandBody, Credit, CreditType, DeleteMovieParams, DownloadRecord, DownloadsResponse,
EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings, IndexerTestResult,
Movie, MovieCommandBody, MovieHistoryItem, RadarrSerdeable, RadarrTask, RadarrTaskName,
ReleaseDownloadBody, SystemStatus, Update,
ReleaseDownloadBody, SystemStatus,
};
use crate::models::servarr_data::radarr::modals::{
AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, IndexerTestResultModalItem,
@@ -20,7 +20,7 @@ use crate::models::servarr_data::radarr::modals::{
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::models::servarr_models::{
AddRootFolderBody, DiskSpace, HostConfig, Indexer, LogResponse, QualityProfile, QueueEvent,
Release, RootFolder, SecurityConfig, Tag,
Release, RootFolder, SecurityConfig, Tag, Update,
};
use crate::models::stateful_table::StatefulTable;
use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText};
@@ -244,7 +244,7 @@ impl<'a, 'b> Network<'a, 'b> {
RadarrEvent::GetStatus => self.get_radarr_status().await.map(RadarrSerdeable::from),
RadarrEvent::GetTags => self.get_radarr_tags().await.map(RadarrSerdeable::from),
RadarrEvent::GetTasks => self.get_radarr_tasks().await.map(RadarrSerdeable::from),
RadarrEvent::GetUpdates => self.get_updates().await.map(RadarrSerdeable::from),
RadarrEvent::GetUpdates => self.get_radarr_updates().await.map(RadarrSerdeable::from),
RadarrEvent::HealthCheck => self
.get_radarr_healthcheck()
.await
@@ -1870,7 +1870,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn get_updates(&mut self) -> Result<Vec<Update>> {
async fn get_radarr_updates(&mut self) -> Result<Vec<Update>> {
info!("Fetching Radarr updates");
let event = RadarrEvent::GetUpdates;
+1 -1
View File
@@ -2730,7 +2730,7 @@ mod test {
}
#[tokio::test]
async fn test_handle_get_updates_event() {
async fn test_handle_get_radarr_updates_event() {
let updates_json = json!([{
"version": "4.3.2.1",
"releaseDate": "2023-04-15T02:02:53Z",
+82 -1
View File
@@ -11,7 +11,7 @@ use crate::{
},
servarr_models::{
AddRootFolderBody, DiskSpace, HostConfig, Indexer, LogResponse, QualityProfile, QueueEvent,
Release, RootFolder, SecurityConfig, Tag,
Release, RootFolder, SecurityConfig, Tag, Update,
},
sonarr_models::{
BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, IndexerSettings, Series,
@@ -59,6 +59,7 @@ pub enum SonarrEvent {
GetSeriesDetails(Option<i64>),
GetSeriesHistory(Option<i64>),
GetStatus,
GetUpdates,
GetTags,
GetTasks,
HealthCheck,
@@ -90,6 +91,7 @@ impl NetworkResource for SonarrEvent {
SonarrEvent::GetSeriesHistory(_) => "/history/series",
SonarrEvent::GetStatus => "/system/status",
SonarrEvent::GetTasks => "/system/task",
SonarrEvent::GetUpdates => "/update",
SonarrEvent::HealthCheck => "/health",
SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) => "/series",
SonarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
@@ -205,6 +207,7 @@ impl<'a, 'b> Network<'a, 'b> {
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::GetUpdates => self.get_sonarr_updates().await.map(SonarrSerdeable::from),
SonarrEvent::HealthCheck => self
.get_sonarr_healthcheck()
.await
@@ -1174,6 +1177,84 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn get_sonarr_updates(&mut self) -> Result<Vec<Update>> {
info!("Fetching Sonarr updates");
let event = SonarrEvent::GetUpdates;
let request_props = self
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
.await;
self
.handle_request::<(), Vec<Update>>(request_props, |updates_vec, mut app| {
let latest_installed = if updates_vec
.iter()
.any(|update| update.latest && update.installed_on.is_some())
{
"already".to_owned()
} else {
"not".to_owned()
};
let updates = updates_vec
.into_iter()
.map(|update| {
let install_status = if update.installed_on.is_some() {
if update.installed {
"(Currently Installed)".to_owned()
} else {
"(Previously Installed)".to_owned()
}
} else {
String::new()
};
let vec_to_bullet_points = |vec: Vec<String>| {
vec
.iter()
.map(|change| format!(" * {change}"))
.collect::<Vec<String>>()
.join("\n")
};
let mut update_info = formatdoc!(
"{} - {} {install_status}
{}",
update.version,
update.release_date,
"-".repeat(200)
);
if let Some(new_changes) = update.changes.new {
let changes = vec_to_bullet_points(new_changes);
update_info = formatdoc!(
"{update_info}
New:
{changes}"
)
}
if let Some(fixes) = update.changes.fixed {
let fixes = vec_to_bullet_points(fixes);
update_info = formatdoc!(
"{update_info}
Fixed:
{fixes}"
);
}
update_info
})
.reduce(|version_1, version_2| format!("{version_1}\n\n\n{version_2}"))
.unwrap();
app.data.sonarr_data.updates = ScrollableText::with_string(formatdoc!(
"The latest version of Sonarr is {latest_installed} installed
{updates}"
));
})
.await
}
async fn mark_sonarr_history_item_as_failed(&mut self, history_item_id: i64) -> Result<Value> {
info!("Marking the Sonarr history item with ID: {history_item_id} as 'failed'");
let event = SonarrEvent::MarkHistoryItemAsFailed(history_item_id);
+98 -2
View File
@@ -18,7 +18,7 @@ mod test {
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::servarr_models::{
DiskSpace, HostConfig, Indexer, IndexerField, Language, LogResponse, Quality, QualityProfile,
QualityWrapper, QueueEvent, Release, RootFolder, SecurityConfig, Tag,
QualityWrapper, QueueEvent, Release, RootFolder, SecurityConfig, Tag, Update,
};
use crate::models::sonarr_models::{
BlocklistItem, DownloadRecord, DownloadsResponse, Episode, EpisodeFile, MediaInfo,
@@ -29,8 +29,8 @@ mod test {
};
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};
use crate::models::{HorizontallyScrollableText, ScrollableText};
use crate::network::sonarr_network::get_episode_status;
use crate::{
@@ -219,6 +219,7 @@ mod test {
#[case(SonarrEvent::GetQualityProfiles, "/qualityprofile")]
#[case(SonarrEvent::GetStatus, "/system/status")]
#[case(SonarrEvent::GetTasks, "/system/task")]
#[case(SonarrEvent::GetUpdates, "/update")]
#[case(SonarrEvent::MarkHistoryItemAsFailed(0), "/history/failed")]
fn test_resource(#[case] event: SonarrEvent, #[case] expected_uri: String) {
assert_str_eq!(event.resource(), expected_uri);
@@ -3741,6 +3742,101 @@ mod test {
}
}
#[tokio::test]
async fn test_handle_get_sonarr_updates_event() {
let updates_json = json!([{
"version": "4.3.2.1",
"releaseDate": "2023-04-15T02:02:53Z",
"installed": true,
"installedOn": "2023-04-15T02:02:53Z",
"latest": true,
"changes": {
"new": [
"Cool new thing"
],
"fixed": [
"Some bugs killed"
]
},
},
{
"version": "3.2.1.0",
"releaseDate": "2023-04-15T02:02:53Z",
"installed": false,
"installedOn": "2023-04-15T02:02:53Z",
"latest": false,
"changes": {
"new": [
"Cool new thing (old)",
"Other cool new thing (old)"
],
},
},
{
"version": "2.1.0",
"releaseDate": "2023-04-15T02:02:53Z",
"installed": false,
"latest": false,
"changes": {
"fixed": [
"Killed bug 1",
"Fixed bug 2"
]
},
}]);
let response: Vec<Update> = serde_json::from_value(updates_json.clone()).unwrap();
let line_break = "-".repeat(200);
let expected_text = ScrollableText::with_string(formatdoc!(
"
The latest version of Sonarr is already installed
4.3.2.1 - 2023-04-15 02:02:53 UTC (Currently Installed)
{line_break}
New:
* Cool new thing
Fixed:
* Some bugs killed
3.2.1.0 - 2023-04-15 02:02:53 UTC (Previously Installed)
{line_break}
New:
* Cool new thing (old)
* Other cool new thing (old)
2.1.0 - 2023-04-15 02:02:53 UTC
{line_break}
Fixed:
* Killed bug 1
* Fixed bug 2"
));
let (async_server, app_arc, _server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(updates_json),
None,
SonarrEvent::GetUpdates,
None,
None,
)
.await;
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let SonarrSerdeable::Updates(updates) = network
.handle_sonarr_event(SonarrEvent::GetUpdates)
.await
.unwrap()
{
async_server.assert_async().await;
assert_str_eq!(
app_arc.lock().await.data.sonarr_data.updates.get_text(),
expected_text.get_text()
);
assert_eq!(updates, response);
}
}
#[tokio::test]
async fn test_handle_mark_sonarr_history_item_as_failed_event() {
let expected_history_item_id = 1;