1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-09-11 12:02:35 +02:00

New: Add OnDelete Notification to TraktConnection

to remove movies from Trakt Collection when they are removed from Radarr

Add OnDelete Notification to TraktConnection to remove movies from Trakt Collection when they are removed from Radarr

skip the deleteHandler if the delete Event was triggered for reason: Upgrade

change migration from 180 to 182 since 180 and 181 are already in plan
to be used

address comments regarding helpText for OnDelete
and move check for OnUpgrade deletion reason into trakt connection OnDelete handler

reuse TraktCollectMoviesResource for OnDelete
trakt api should just ignore the other properties anyway

add WithDefaultValue to migration

add unit test case for onDelete to

fix unit testcase for onDelete
This commit is contained in:
geogolem 2020-08-16 00:32:53 -04:00 committed by Qstick
parent 261e598c99
commit e033ce1eff
17 changed files with 171 additions and 3 deletions

View File

@ -59,11 +59,13 @@ class Notification extends Component {
onDownload,
onUpgrade,
onRename,
onDelete,
onHealthIssue,
supportsOnGrab,
supportsOnDownload,
supportsOnUpgrade,
supportsOnRename,
supportsOnDelete,
supportsOnHealthIssue
} = this.props;
@ -84,6 +86,13 @@ class Notification extends Component {
</Label>
}
{
supportsOnDelete && onDelete &&
<Label kind={kinds.SUCCESS}>
On Delete
</Label>
}
{
supportsOnDownload && onDownload &&
<Label kind={kinds.SUCCESS}>
@ -113,7 +122,7 @@ class Notification extends Component {
}
{
!onGrab && !onDownload && !onRename && !onHealthIssue &&
!onGrab && !onDownload && !onRename && !onHealthIssue && !onDelete &&
<Label
kind={kinds.DISABLED}
outline={true}
@ -150,9 +159,11 @@ Notification.propTypes = {
onDownload: PropTypes.bool.isRequired,
onUpgrade: PropTypes.bool.isRequired,
onRename: PropTypes.bool.isRequired,
onDelete: PropTypes.bool.isRequired,
onHealthIssue: PropTypes.bool.isRequired,
supportsOnGrab: PropTypes.bool.isRequired,
supportsOnDownload: PropTypes.bool.isRequired,
supportsOnDelete: PropTypes.bool.isRequired,
supportsOnUpgrade: PropTypes.bool.isRequired,
supportsOnRename: PropTypes.bool.isRequired,
supportsOnHealthIssue: PropTypes.bool.isRequired,

View File

@ -19,11 +19,13 @@ function NotificationEventItems(props) {
onDownload,
onUpgrade,
onRename,
onDelete,
onHealthIssue,
supportsOnGrab,
supportsOnDownload,
supportsOnUpgrade,
supportsOnRename,
supportsOnDelete,
supportsOnHealthIssue,
includeHealthWarnings
} = item;
@ -84,6 +86,17 @@ function NotificationEventItems(props) {
/>
</div>
<div>
<FormInputGroup
type={inputTypes.CHECK}
name="onDelete"
helpText="On Delete"
isDisabled={!supportsOnDelete.value}
{...onDelete}
onChange={onInputChange}
/>
</div>
<div>
<FormInputGroup
type={inputTypes.CHECK}

View File

@ -17,10 +17,12 @@ protected override void MapToResource(NotificationResource resource, Notificatio
resource.OnDownload = definition.OnDownload;
resource.OnUpgrade = definition.OnUpgrade;
resource.OnRename = definition.OnRename;
resource.OnDelete = definition.OnDelete;
resource.SupportsOnGrab = definition.SupportsOnGrab;
resource.SupportsOnDownload = definition.SupportsOnDownload;
resource.SupportsOnUpgrade = definition.SupportsOnUpgrade;
resource.SupportsOnRename = definition.SupportsOnRename;
resource.SupportsOnDelete = definition.SupportsOnDelete;
resource.Tags = definition.Tags;
}
@ -32,10 +34,12 @@ protected override void MapToModel(NotificationDefinition definition, Notificati
definition.OnDownload = resource.OnDownload;
definition.OnUpgrade = resource.OnUpgrade;
definition.OnRename = resource.OnRename;
definition.OnDelete = resource.OnDelete;
definition.SupportsOnGrab = resource.SupportsOnGrab;
definition.SupportsOnDownload = resource.SupportsOnDownload;
definition.SupportsOnUpgrade = resource.SupportsOnUpgrade;
definition.SupportsOnRename = resource.SupportsOnRename;
definition.SupportsOnDelete = resource.SupportsOnDelete;
definition.Tags = resource.Tags;
}

View File

@ -8,10 +8,12 @@ public class NotificationResource : ProviderResource
public bool OnDownload { get; set; }
public bool OnUpgrade { get; set; }
public bool OnRename { get; set; }
public bool OnDelete { get; set; }
public bool SupportsOnGrab { get; set; }
public bool SupportsOnDownload { get; set; }
public bool SupportsOnUpgrade { get; set; }
public bool SupportsOnRename { get; set; }
public bool SupportsOnDelete { get; set; }
public HashSet<int> Tags { get; set; }
}
}

View File

@ -62,6 +62,11 @@ public override void OnMovieRename(Movie movie)
TestLogger.Info("OnRename was called");
}
public override void OnDelete(DeleteMessage message)
{
TestLogger.Info("OnDelete was called");
}
public override void OnHealthIssue(NzbDrone.Core.HealthCheck.HealthCheck artist)
{
TestLogger.Info("OnHealthIssue was called");
@ -100,6 +105,7 @@ public void should_support_all_if_implemented()
notification.SupportsOnDownload.Should().BeTrue();
notification.SupportsOnUpgrade.Should().BeTrue();
notification.SupportsOnRename.Should().BeTrue();
notification.SupportsOnDelete.Should().BeTrue();
notification.SupportsOnHealthIssue.Should().BeTrue();
}
@ -112,6 +118,7 @@ public void should_support_none_if_none_are_implemented()
notification.SupportsOnDownload.Should().BeFalse();
notification.SupportsOnUpgrade.Should().BeFalse();
notification.SupportsOnRename.Should().BeFalse();
notification.SupportsOnDelete.Should().BeFalse();
notification.SupportsOnHealthIssue.Should().BeFalse();
}
}

View File

@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(182)]
public class on_delete_notification : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Notifications").AddColumn("OnDelete").AsBoolean().WithDefaultValue(false);
}
}
}

View File

@ -86,6 +86,7 @@ public static void Map()
.Ignore(i => i.SupportsOnDownload)
.Ignore(i => i.SupportsOnUpgrade)
.Ignore(i => i.SupportsOnRename)
.Ignore(i => i.SupportsOnDelete)
.Ignore(i => i.SupportsOnHealthIssue);
Mapper.Entity<MetadataDefinition>("Metadata").RegisterModel()

View File

@ -0,0 +1,20 @@
using System.Collections.Generic;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies;
namespace NzbDrone.Core.Notifications
{
public class DeleteMessage
{
public string Message { get; set; }
public Movie Movie { get; set; }
public MovieFile MovieFile { get; set; }
public DeleteMediaFileReason Reason { get; set; }
public override string ToString()
{
return Message;
}
}
}

View File

@ -11,10 +11,12 @@ public interface INotification : IProvider
void OnDownload(DownloadMessage message);
void OnMovieRename(Movie movie);
void OnHealthIssue(HealthCheck.HealthCheck healthCheck);
void OnDelete(DeleteMessage deleteMessage);
bool SupportsOnGrab { get; }
bool SupportsOnDownload { get; }
bool SupportsOnUpgrade { get; }
bool SupportsOnRename { get; }
bool SupportsOnHealthIssue { get; }
bool SupportsOnDelete { get; }
}
}

View File

@ -46,11 +46,16 @@ public virtual void OnHealthIssue(HealthCheck.HealthCheck healthCheck)
{
}
public virtual void OnDelete(DeleteMessage deleteMessage)
{
}
public bool SupportsOnGrab => HasConcreteImplementation("OnGrab");
public bool SupportsOnRename => HasConcreteImplementation("OnMovieRename");
public bool SupportsOnDownload => HasConcreteImplementation("OnDownload");
public bool SupportsOnUpgrade => SupportsOnDownload;
public bool SupportsOnHealthIssue => HasConcreteImplementation("OnHealthIssue");
public bool SupportsOnDelete => HasConcreteImplementation("OnDelete");
protected TSettings Settings => (TSettings)Definition.Settings;

View File

@ -9,13 +9,15 @@ public class NotificationDefinition : ProviderDefinition
public bool OnUpgrade { get; set; }
public bool OnRename { get; set; }
public bool OnHealthIssue { get; set; }
public bool OnDelete { get; set; }
public bool SupportsOnGrab { get; set; }
public bool SupportsOnDownload { get; set; }
public bool SupportsOnUpgrade { get; set; }
public bool SupportsOnRename { get; set; }
public bool SupportsOnHealthIssue { get; set; }
public bool SupportsOnDelete { get; set; }
public bool IncludeHealthWarnings { get; set; }
public override bool Enable => OnGrab || OnDownload || (OnDownload && OnUpgrade) || OnHealthIssue;
public override bool Enable => OnGrab || OnDownload || (OnDownload && OnUpgrade) || OnHealthIssue || OnDelete;
}
}

View File

@ -14,6 +14,7 @@ public interface INotificationFactory : IProviderFactory<INotification, Notifica
List<INotification> OnUpgradeEnabled();
List<INotification> OnRenameEnabled();
List<INotification> OnHealthIssueEnabled();
List<INotification> OnDeleteEnabled();
}
public class NotificationFactory : ProviderFactory<INotification, NotificationDefinition>, INotificationFactory
@ -48,6 +49,11 @@ public List<INotification> OnHealthIssueEnabled()
return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnHealthIssue).ToList();
}
public List<INotification> OnDeleteEnabled()
{
return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnDelete).ToList();
}
public override void SetProviderCharacteristics(INotification provider, NotificationDefinition definition)
{
base.SetProviderCharacteristics(provider, definition);
@ -57,6 +63,7 @@ public override void SetProviderCharacteristics(INotification provider, Notifica
definition.SupportsOnUpgrade = provider.SupportsOnUpgrade;
definition.SupportsOnRename = provider.SupportsOnRename;
definition.SupportsOnHealthIssue = provider.SupportsOnHealthIssue;
definition.SupportsOnDelete = provider.SupportsOnDelete;
}
}
}

View File

@ -16,7 +16,8 @@ public class NotificationService
: IHandle<MovieRenamedEvent>,
IHandle<MovieGrabbedEvent>,
IHandle<MovieDownloadedEvent>,
IHandle<HealthCheckFailedEvent>
IHandle<HealthCheckFailedEvent>,
IHandle<MovieFileDeletedEvent>
{
private readonly INotificationFactory _notificationFactory;
private readonly Logger _logger;
@ -172,5 +173,29 @@ public void Handle(HealthCheckFailedEvent message)
}
}
}
public void Handle(MovieFileDeletedEvent message)
{
var deleteMessage = new DeleteMessage();
deleteMessage.Message = GetMessage(message.MovieFile.Movie, message.MovieFile.Quality);
deleteMessage.MovieFile = message.MovieFile;
deleteMessage.Movie = message.MovieFile.Movie;
deleteMessage.Reason = message.Reason;
foreach (var notification in _notificationFactory.OnDeleteEnabled())
{
try
{
if (ShouldHandleMovie(notification.Definition, message.MovieFile.Movie))
{
notification.OnDelete(deleteMessage);
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnDelete notification to: " + notification.Definition.Name);
}
}
}
}
}

View File

@ -29,6 +29,14 @@ public override void OnDownload(DownloadMessage message)
_traktService.AddMovieToCollection(Settings, message.Movie, message.MovieFile);
}
public override void OnDelete(DeleteMessage message)
{
if (message.Reason != MediaFiles.DeleteMediaFileReason.Upgrade)
{
_traktService.RemoveMovieFromCollection(Settings, message.Movie, message.MovieFile);
}
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();

View File

@ -12,6 +12,7 @@ public interface ITraktProxy
HttpRequest GetOAuthRequest(string callbackUrl);
TraktAuthRefreshResource RefreshAuthToken(string refreshToken);
void AddToCollection(TraktCollectMoviesResource payload, string accessToken);
void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken);
HttpRequest BuildTraktRequest(string resource, HttpMethod method, string accessToken);
}
@ -50,6 +51,24 @@ public void AddToCollection(TraktCollectMoviesResource payload, string accessTok
}
}
public void RemoveFromCollection(TraktCollectMoviesResource payload, string accessToken)
{
var request = BuildTraktRequest("sync/collection/remove", HttpMethod.POST, accessToken);
request.Headers.ContentType = "application/json";
request.SetContent(payload.ToJson());
try
{
_httpClient.Execute(request);
}
catch (HttpException ex)
{
_logger.Error(ex, "Unable to post payload {0}", payload);
throw new TraktException("Unable to post payload", ex);
}
}
public string GetUserName(string accessToken)
{
var request = BuildTraktRequest("users/settings", HttpMethod.GET, accessToken);

View File

@ -19,6 +19,7 @@ public interface ITraktService
HttpRequest GetOAuthRequest(string callbackUrl);
TraktAuthRefreshResource RefreshAuthToken(string refreshToken);
void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile);
void RemoveMovieFromCollection(TraktSettings settings, Movie movie, MovieFile movieFile);
string GetUserName(string accessToken);
ValidationFailure Test(TraktSettings settings);
}
@ -75,6 +76,27 @@ public ValidationFailure Test(TraktSettings settings)
}
}
public void RemoveMovieFromCollection(TraktSettings settings, Movie movie, MovieFile movieFile)
{
var payload = new TraktCollectMoviesResource
{
Movies = new List<TraktCollectMovie>()
};
payload.Movies.Add(new TraktCollectMovie
{
Title = movie.Title,
Year = movie.Year,
Ids = new TraktMovieIdsResource
{
Tmdb = movie.TmdbId,
Imdb = movie.ImdbId ?? "",
}
});
_proxy.RemoveFromCollection(payload, settings.AccessToken);
}
public void AddMovieToCollection(TraktSettings settings, Movie movie, MovieFile movieFile)
{
var payload = new TraktCollectMoviesResource

View File

@ -9,11 +9,13 @@ public class NotificationResource : ProviderResource
public bool OnDownload { get; set; }
public bool OnUpgrade { get; set; }
public bool OnRename { get; set; }
public bool OnDelete { get; set; }
public bool OnHealthIssue { get; set; }
public bool SupportsOnGrab { get; set; }
public bool SupportsOnDownload { get; set; }
public bool SupportsOnUpgrade { get; set; }
public bool SupportsOnRename { get; set; }
public bool SupportsOnDelete { get; set; }
public bool SupportsOnHealthIssue { get; set; }
public bool IncludeHealthWarnings { get; set; }
public string TestCommand { get; set; }
@ -34,11 +36,13 @@ public override NotificationResource ToResource(NotificationDefinition definitio
resource.OnDownload = definition.OnDownload;
resource.OnUpgrade = definition.OnUpgrade;
resource.OnRename = definition.OnRename;
resource.OnDelete = definition.OnDelete;
resource.OnHealthIssue = definition.OnHealthIssue;
resource.SupportsOnGrab = definition.SupportsOnGrab;
resource.SupportsOnDownload = definition.SupportsOnDownload;
resource.SupportsOnUpgrade = definition.SupportsOnUpgrade;
resource.SupportsOnRename = definition.SupportsOnRename;
resource.SupportsOnDelete = definition.SupportsOnDelete;
resource.SupportsOnHealthIssue = definition.SupportsOnHealthIssue;
resource.IncludeHealthWarnings = definition.IncludeHealthWarnings;
@ -58,11 +62,13 @@ public override NotificationDefinition ToModel(NotificationResource resource)
definition.OnDownload = resource.OnDownload;
definition.OnUpgrade = resource.OnUpgrade;
definition.OnRename = resource.OnRename;
definition.OnDelete = resource.OnDelete;
definition.OnHealthIssue = resource.OnHealthIssue;
definition.SupportsOnGrab = resource.SupportsOnGrab;
definition.SupportsOnDownload = resource.SupportsOnDownload;
definition.SupportsOnUpgrade = resource.SupportsOnUpgrade;
definition.SupportsOnRename = resource.SupportsOnRename;
definition.SupportsOnDelete = resource.SupportsOnDelete;
definition.SupportsOnHealthIssue = resource.SupportsOnHealthIssue;
definition.IncludeHealthWarnings = resource.IncludeHealthWarnings;