feat(network): Support for deleting a series from Sonarr

This commit is contained in:
2024-11-23 12:42:11 -07:00
parent 374819b4f3
commit cac54c5447
5 changed files with 164 additions and 7 deletions
@@ -20,7 +20,9 @@ use super::modals::SeasonDetailsModal;
mod sonarr_data_tests;
pub struct SonarrData {
pub add_list_exclusion: bool,
pub blocklist: StatefulTable<BlocklistItem>,
pub delete_series_files: bool,
pub downloads: StatefulTable<DownloadRecord>,
pub disk_space_vec: Vec<DiskSpace>,
pub edit_root_folder: Option<HorizontallyScrollableText>,
@@ -44,11 +46,20 @@ pub struct SonarrData {
pub version: String,
}
impl SonarrData {
pub fn reset_delete_series_preferences(&mut self) {
self.delete_series_files = false;
self.add_list_exclusion = false;
}
}
impl Default for SonarrData {
fn default() -> SonarrData {
SonarrData {
add_list_exclusion: false,
blocklist: StatefulTable::default(),
downloads: StatefulTable::default(),
delete_series_files: false,
disk_space_vec: Vec::new(),
edit_root_folder: None,
history: StatefulTable::default(),
@@ -97,6 +108,8 @@ pub enum ActiveSonarrBlock {
DeleteRootFolderPrompt,
DeleteSeriesConfirmPrompt,
DeleteSeriesPrompt,
DeleteSeriesToggleAddListExclusion,
DeleteSeriesToggleDeleteFile,
Downloads,
EditEpisodePrompt,
EditIndexerPrompt,
@@ -30,11 +30,27 @@ mod tests {
);
}
#[test]
fn test_reset_delete_series_preferences() {
let mut sonarr_data = SonarrData {
add_list_exclusion: true,
delete_series_files: true,
..SonarrData::default()
};
sonarr_data.reset_delete_series_preferences();
assert!(!sonarr_data.delete_series_files);
assert!(!sonarr_data.add_list_exclusion);
}
#[test]
fn test_sonarr_data_defaults() {
let sonarr_data = SonarrData::default();
assert!(!sonarr_data.add_list_exclusion);
assert!(sonarr_data.blocklist.is_empty());
assert!(!sonarr_data.delete_series_files);
assert!(sonarr_data.downloads.is_empty());
assert!(sonarr_data.disk_space_vec.is_empty());
assert!(sonarr_data.edit_root_folder.is_none());
+8
View File
@@ -44,6 +44,14 @@ pub struct BlocklistResponse {
pub records: Vec<BlocklistItem>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub struct DeleteSeriesParams {
pub id: i64,
pub delete_series_files: bool,
pub add_list_exclusion: bool,
}
#[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DownloadRecord {
+60 -4
View File
@@ -18,9 +18,10 @@ use crate::{
QueueEvent, RootFolder, SecurityConfig, Tag, Update,
},
sonarr_models::{
BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, IndexerSettings, Series,
SonarrCommandBody, SonarrHistoryItem, SonarrHistoryWrapper, SonarrRelease,
SonarrReleaseDownloadBody, SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus,
BlocklistResponse, DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode,
IndexerSettings, Series, SonarrCommandBody, SonarrHistoryItem, SonarrHistoryWrapper,
SonarrRelease, SonarrReleaseDownloadBody, SonarrSerdeable, SonarrTask, SonarrTaskName,
SystemStatus,
},
stateful_table::StatefulTable,
HorizontallyScrollableText, Route, Scrollable, ScrollableText,
@@ -43,6 +44,7 @@ pub enum SonarrEvent {
DeleteDownload(Option<i64>),
DeleteIndexer(Option<i64>),
DeleteRootFolder(Option<i64>),
DeleteSeries(Option<DeleteSeriesParams>),
DeleteTag(i64),
DownloadRelease(SonarrReleaseDownloadBody),
GetAllIndexerSettings,
@@ -116,7 +118,9 @@ impl NetworkResource for SonarrEvent {
SonarrEvent::GetTasks => "/system/task",
SonarrEvent::GetUpdates => "/update",
SonarrEvent::HealthCheck => "/health",
SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) => "/series",
SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) | SonarrEvent::DeleteSeries(_) => {
"/series"
}
SonarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
SonarrEvent::TestIndexer(_) => "/indexer/test",
SonarrEvent::TestAllIndexers => "/indexer/testall",
@@ -165,6 +169,9 @@ impl<'a, 'b> Network<'a, 'b> {
.delete_sonarr_root_folder(root_folder_id)
.await
.map(SonarrSerdeable::from),
SonarrEvent::DeleteSeries(params) => {
self.delete_series(params).await.map(SonarrSerdeable::from)
}
SonarrEvent::DeleteTag(tag_id) => self
.delete_sonarr_tag(tag_id)
.await
@@ -498,6 +505,55 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn delete_series(
&mut self,
delete_series_params: Option<DeleteSeriesParams>,
) -> Result<()> {
let event = SonarrEvent::DeleteSeries(None);
let (series_id, delete_files, add_import_exclusion) = if let Some(params) = delete_series_params
{
(
params.id,
params.delete_series_files,
params.add_list_exclusion,
)
} else {
let (series_id, _) = self.extract_series_id(None).await;
let delete_files = self.app.lock().await.data.sonarr_data.delete_series_files;
let add_import_exclusion = self.app.lock().await.data.sonarr_data.add_list_exclusion;
(series_id, delete_files, add_import_exclusion)
};
info!("Deleting Sonarr series with ID: {series_id} with deleteFiles={delete_files} and addImportExclusion={add_import_exclusion}");
let request_props = self
.request_props_from(
event,
RequestMethod::Delete,
None::<()>,
Some(format!("/{series_id}")),
Some(format!(
"deleteFiles={delete_files}&addImportExclusion={add_import_exclusion}"
)),
)
.await;
let resp = self
.handle_request::<(), ()>(request_props, |_, _| ())
.await;
self
.app
.lock()
.await
.data
.sonarr_data
.reset_delete_series_preferences();
resp
}
async fn delete_sonarr_tag(&mut self, id: i64) -> Result<()> {
info!("Deleting Sonarr tag with id: {id}");
let event = SonarrEvent::DeleteTag(id);
+67 -3
View File
@@ -24,8 +24,8 @@ mod test {
QualityWrapper, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
};
use crate::models::sonarr_models::{
BlocklistItem, DownloadRecord, DownloadsResponse, Episode, EpisodeFile, MediaInfo,
SonarrRelease, SonarrReleaseDownloadBody, SonarrTaskName,
BlocklistItem, DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode, EpisodeFile,
MediaInfo, SonarrRelease, SonarrReleaseDownloadBody, SonarrTaskName,
};
use crate::models::sonarr_models::{
BlocklistResponse, SonarrHistoryData, SonarrHistoryItem, SonarrHistoryWrapper,
@@ -137,7 +137,12 @@ mod test {
#[rstest]
fn test_resource_series(
#[values(SonarrEvent::ListSeries, SonarrEvent::GetSeriesDetails(None))] event: SonarrEvent,
#[values(
SonarrEvent::ListSeries,
SonarrEvent::GetSeriesDetails(None),
SonarrEvent::DeleteSeries(None)
)]
event: SonarrEvent,
) {
assert_str_eq!(event.resource(), "/series");
}
@@ -577,6 +582,65 @@ mod test {
async_server.assert_async().await;
}
#[tokio::test]
async fn test_handle_delete_series_event() {
let (async_server, app_arc, _server) = mock_servarr_api(
RequestMethod::Delete,
None,
None,
None,
SonarrEvent::DeleteSeries(None),
Some("/1"),
Some("deleteFiles=true&addImportExclusion=true"),
)
.await;
{
let mut app = app_arc.lock().await;
app.data.sonarr_data.series.set_items(vec![series()]);
app.data.sonarr_data.delete_series_files = true;
app.data.sonarr_data.add_list_exclusion = true;
}
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network
.handle_sonarr_event(SonarrEvent::DeleteSeries(None))
.await
.is_ok());
async_server.assert_async().await;
assert!(!app_arc.lock().await.data.sonarr_data.delete_series_files);
assert!(!app_arc.lock().await.data.sonarr_data.add_list_exclusion);
}
#[tokio::test]
async fn test_handle_delete_series_event_use_provided_params() {
let (async_server, app_arc, _server) = mock_servarr_api(
RequestMethod::Delete,
None,
None,
None,
SonarrEvent::DeleteSeries(None),
Some("/1"),
Some("deleteFiles=true&addImportExclusion=true"),
)
.await;
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let delete_series_params = DeleteSeriesParams {
id: 1,
delete_series_files: true,
add_list_exclusion: true,
};
assert!(network
.handle_sonarr_event(SonarrEvent::DeleteSeries(Some(delete_series_params)))
.await
.is_ok());
async_server.assert_async().await;
assert!(!app_arc.lock().await.data.sonarr_data.delete_series_files);
assert!(!app_arc.lock().await.data.sonarr_data.add_list_exclusion);
}
#[tokio::test]
async fn test_handle_delete_sonarr_tag_event() {
let (async_server, app_arc, _server) = mock_servarr_api(