From a86aa4c5d3315a6cea59bd23d3dac9fca539bec1 Mon Sep 17 00:00:00 2001 From: The Dark <12370876+CheAle14@users.noreply.github.com> Date: Mon, 8 May 2023 02:57:14 +0100 Subject: [PATCH] New: On Health Restored notification (cherry picked from commit 5fdc8514da7c7ad98192f2ecb2415b3a7b5d0d05) --- .../Notifications/Notification.js | 24 +++++++++++++---- .../Notifications/NotificationEventItems.js | 15 ++++++++++- .../NotificationBaseFixture.cs | 7 +++++ .../032_health_restored_notification.cs | 14 ++++++++++ src/NzbDrone.Core/Datastore/TableMapping.cs | 1 + .../HealthCheck/HealthCheckRestoredEvent.cs | 16 ++++++++++++ .../HealthCheck/HealthCheckService.cs | 7 +++++ src/NzbDrone.Core/Localization/Core/en.json | 2 ++ .../Notifications/Apprise/Apprise.cs | 5 ++++ .../Notifications/Boxcar/Boxcar.cs | 5 ++++ .../CustomScript/CustomScript.cs | 15 +++++++++++ .../Notifications/Discord/Discord.cs | 23 ++++++++++++++++ .../Notifications/Email/Email.cs | 5 ++++ .../Notifications/Gotify/Gotify.cs | 5 ++++ .../Notifications/INotification.cs | 2 ++ src/NzbDrone.Core/Notifications/Join/Join.cs | 5 ++++ .../Notifications/Mailgun/Mailgun.cs | 5 ++++ .../Notifications/Notifiarr/Notifiarr.cs | 5 ++++ .../Notifications/NotificationBase.cs | 7 +++++ .../Notifications/NotificationDefinition.cs | 4 ++- .../Notifications/NotificationFactory.cs | 7 +++++ .../Notifications/NotificationService.cs | 26 +++++++++++++++++-- src/NzbDrone.Core/Notifications/Ntfy/Ntfy.cs | 5 ++++ .../Notifications/Prowl/Prowl.cs | 5 ++++ .../Notifications/PushBullet/PushBullet.cs | 5 ++++ .../Notifications/Pushover/Pushover.cs | 5 ++++ .../Notifications/SendGrid/SendGrid.cs | 5 ++++ .../Notifications/Simplepush/Simplepush.cs | 5 ++++ .../Notifications/Slack/Slack.cs | 17 ++++++++++++ .../Notifications/Telegram/Telegram.cs | 5 ++++ .../Notifications/Twitter/Twitter.cs | 5 ++++ .../Notifications/Webhook/Webhook.cs | 5 ++++ .../Notifications/Webhook/WebhookBase.cs | 13 ++++++++++ .../Notifications/Webhook/WebhookEventType.cs | 3 ++- .../Notifications/NotificationResource.cs | 6 +++++ 35 files changed, 279 insertions(+), 10 deletions(-) create mode 100644 src/NzbDrone.Core/Datastore/Migration/032_health_restored_notification.cs create mode 100644 src/NzbDrone.Core/HealthCheck/HealthCheckRestoredEvent.cs diff --git a/frontend/src/Settings/Notifications/Notifications/Notification.js b/frontend/src/Settings/Notifications/Notifications/Notification.js index 1331a7c8b..66021fd0d 100644 --- a/frontend/src/Settings/Notifications/Notifications/Notification.js +++ b/frontend/src/Settings/Notifications/Notifications/Notification.js @@ -57,9 +57,11 @@ class Notification extends Component { name, onGrab, onHealthIssue, + onHealthRestored, onApplicationUpdate, supportsOnGrab, supportsOnHealthIssue, + supportsOnHealthRestored, supportsOnApplicationUpdate } = this.props; @@ -74,17 +76,27 @@ class Notification extends Component { </div> { - supportsOnGrab && onGrab && + supportsOnGrab && onGrab ? <Label kind={kinds.SUCCESS}> {translate('OnGrab')} - </Label> + </Label> : + null } { - supportsOnHealthIssue && onHealthIssue && + supportsOnHealthIssue && onHealthIssue ? <Label kind={kinds.SUCCESS}> {translate('OnHealthIssue')} - </Label> + </Label> : + null + } + + { + supportsOnHealthRestored && onHealthRestored ? + <Label kind={kinds.SUCCESS}> + {translate('OnHealthRestored')} + </Label> : + null } { @@ -96,7 +108,7 @@ class Notification extends Component { } { - !onGrab && !onHealthIssue && !onApplicationUpdate ? + !onGrab && !onHealthIssue && !onHealthRestored && !onApplicationUpdate ? <Label kind={kinds.DISABLED} outline={true} @@ -132,9 +144,11 @@ Notification.propTypes = { name: PropTypes.string.isRequired, onGrab: PropTypes.bool.isRequired, onHealthIssue: PropTypes.bool.isRequired, + onHealthRestored: PropTypes.bool.isRequired, onApplicationUpdate: PropTypes.bool.isRequired, supportsOnGrab: PropTypes.bool.isRequired, supportsOnHealthIssue: PropTypes.bool.isRequired, + supportsOnHealthRestored: PropTypes.bool.isRequired, supportsOnApplicationUpdate: PropTypes.bool.isRequired, onConfirmDeleteNotification: PropTypes.func.isRequired }; diff --git a/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js b/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js index 153842692..1508b029f 100644 --- a/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js +++ b/frontend/src/Settings/Notifications/Notifications/NotificationEventItems.js @@ -17,10 +17,12 @@ function NotificationEventItems(props) { const { onGrab, onHealthIssue, + onHealthRestored, onApplicationUpdate, supportsOnGrab, includeManualGrabs, supportsOnHealthIssue, + supportsOnHealthRestored, includeHealthWarnings, supportsOnApplicationUpdate } = item; @@ -70,8 +72,19 @@ function NotificationEventItems(props) { /> </div> + <div> + <FormInputGroup + type={inputTypes.CHECK} + name="onHealthRestored" + helpText={translate('OnHealthRestoredHelpText')} + isDisabled={!supportsOnHealthRestored.value} + {...onHealthRestored} + onChange={onInputChange} + /> + </div> + { - onHealthIssue.value && + (onHealthIssue.value || onHealthRestored.value) && <div> <FormInputGroup type={inputTypes.CHECK} diff --git a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs index 366687860..42c92c909 100644 --- a/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs +++ b/src/NzbDrone.Core.Test/NotificationTests/NotificationBaseFixture.cs @@ -51,6 +51,11 @@ namespace NzbDrone.Core.Test.NotificationTests TestLogger.Info("OnHealthIssue was called"); } + public override void OnHealthRestored(Core.HealthCheck.HealthCheck healthCheck) + { + TestLogger.Info("OnHealthRestored was called"); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { TestLogger.Info("OnApplicationUpdate was called"); @@ -79,6 +84,7 @@ namespace NzbDrone.Core.Test.NotificationTests var notification = new TestNotificationWithAllEvents(); notification.SupportsOnHealthIssue.Should().BeTrue(); + notification.SupportsOnHealthRestored.Should().BeTrue(); notification.SupportsOnApplicationUpdate.Should().BeTrue(); notification.SupportsOnGrab.Should().BeTrue(); } @@ -89,6 +95,7 @@ namespace NzbDrone.Core.Test.NotificationTests var notification = new TestNotificationWithNoEvents(); notification.SupportsOnHealthIssue.Should().BeFalse(); + notification.SupportsOnHealthRestored.Should().BeFalse(); notification.SupportsOnApplicationUpdate.Should().BeFalse(); notification.SupportsOnGrab.Should().BeFalse(); } diff --git a/src/NzbDrone.Core/Datastore/Migration/032_health_restored_notification.cs b/src/NzbDrone.Core/Datastore/Migration/032_health_restored_notification.cs new file mode 100644 index 000000000..81ed4a209 --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/032_health_restored_notification.cs @@ -0,0 +1,14 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(032)] + public class health_restored_notification : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Alter.Table("Notifications").AddColumn("OnHealthRestored").AsBoolean().WithDefaultValue(0); + } + } +} diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 93f4616d4..aa87b40f2 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -69,6 +69,7 @@ namespace NzbDrone.Core.Datastore .Ignore(x => x.ImplementationName) .Ignore(i => i.SupportsOnGrab) .Ignore(i => i.SupportsOnHealthIssue) + .Ignore(i => i.SupportsOnHealthRestored) .Ignore(i => i.SupportsOnApplicationUpdate); Mapper.Entity<IndexerProxyDefinition>("IndexerProxies").RegisterModel() diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckRestoredEvent.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckRestoredEvent.cs new file mode 100644 index 000000000..a31b63cc4 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckRestoredEvent.cs @@ -0,0 +1,16 @@ +using NzbDrone.Common.Messaging; + +namespace NzbDrone.Core.HealthCheck +{ + public class HealthCheckRestoredEvent : IEvent + { + public HealthCheck PreviousCheck { get; private set; } + public bool IsInStartupGracePeriod { get; private set; } + + public HealthCheckRestoredEvent(HealthCheck previousCheck, bool isInStartupGracePeriod) + { + PreviousCheck = previousCheck; + IsInStartupGracePeriod = isInStartupGracePeriod; + } + } +} diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index 1538674ab..11ae42719 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -91,6 +91,13 @@ namespace NzbDrone.Core.HealthCheck { if (result.Type == HealthCheckResult.Ok) { + var previous = _healthCheckResults.Find(result.Source.Name); + + if (previous != null) + { + _eventAggregator.PublishEvent(new HealthCheckRestoredEvent(previous, !_hasRunHealthChecksAfterGracePeriod)); + } + _healthCheckResults.Remove(result.Source.Name); } else diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 77db15c79..48d631a9a 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -294,6 +294,8 @@ "OnGrabHelpText": "On Release Grab", "OnHealthIssue": "On Health Issue", "OnHealthIssueHelpText": "On Health Issue", + "OnHealthRestored": "On Health Restored", + "OnHealthRestoredHelpText": "On Health Restored", "OpenBrowserOnStart": "Open browser on start", "OpenThisModal": "Open This Modal", "Options": "Options", diff --git a/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs b/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs index d2b896b3f..ef84b743c 100644 --- a/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs +++ b/src/NzbDrone.Core/Notifications/Apprise/Apprise.cs @@ -27,6 +27,11 @@ namespace NzbDrone.Core.Notifications.Apprise _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE_BRANDED, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs index c4caa0435..c1f616d5a 100644 --- a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs +++ b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs @@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Boxcar _proxy.SendNotification(HEALTH_ISSUE_TITLE, message.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage message) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE, message.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs index 13dfa8478..f87917468 100755 --- a/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs +++ b/src/NzbDrone.Core/Notifications/CustomScript/CustomScript.cs @@ -55,6 +55,21 @@ namespace NzbDrone.Core.Notifications.CustomScript ExecuteScript(environmentVariables); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + var environmentVariables = new StringDictionary(); + + environmentVariables.Add("Prowlarr_EventType", "HealthRestored"); + environmentVariables.Add("Prowlarr_InstanceName", _configFileProvider.InstanceName); + environmentVariables.Add("Prowlarr_ApplicationUrl", _configService.ApplicationUrl); + environmentVariables.Add("Prowlarr_Health_Restored_Level", Enum.GetName(typeof(HealthCheckResult), previousCheck.Type)); + environmentVariables.Add("Prowlarr_Health_Restored_Message", previousCheck.Message); + environmentVariables.Add("Prowlarr_Health_Restored_Type", previousCheck.Source.Name); + environmentVariables.Add("Prowlarr_Health_Restored_Wiki", previousCheck.WikiUrl.ToString() ?? string.Empty); + + ExecuteScript(environmentVariables); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { var environmentVariables = new StringDictionary(); diff --git a/src/NzbDrone.Core/Notifications/Discord/Discord.cs b/src/NzbDrone.Core/Notifications/Discord/Discord.cs index ca69464a4..9eb41e989 100644 --- a/src/NzbDrone.Core/Notifications/Discord/Discord.cs +++ b/src/NzbDrone.Core/Notifications/Discord/Discord.cs @@ -101,6 +101,29 @@ namespace NzbDrone.Core.Notifications.Discord _proxy.SendPayload(payload, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + var attachments = new List<Embed> + { + new Embed + { + Author = new DiscordAuthor + { + Name = Settings.Author.IsNullOrWhiteSpace() ? Environment.MachineName : Settings.Author, + IconUrl = "https://raw.githubusercontent.com/Prowlarr/Prowlarr/develop/Logo/256.png" + }, + Title = "Health Issue Resolved: " + previousCheck.Source.Name, + Description = $"The following issue is now resolved: {previousCheck.Message}", + Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"), + Color = (int)DiscordColors.Success + } + }; + + var payload = CreatePayload(null, attachments); + + _proxy.SendPayload(payload, Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { var attachments = new List<Embed> diff --git a/src/NzbDrone.Core/Notifications/Email/Email.cs b/src/NzbDrone.Core/Notifications/Email/Email.cs index 5bbb76867..6f09eec92 100644 --- a/src/NzbDrone.Core/Notifications/Email/Email.cs +++ b/src/NzbDrone.Core/Notifications/Email/Email.cs @@ -36,6 +36,11 @@ namespace NzbDrone.Core.Notifications.Email SendEmail(Settings, HEALTH_ISSUE_TITLE_BRANDED, message.Message); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousMessage) + { + SendEmail(Settings, HEALTH_RESTORED_TITLE_BRANDED, $"The following issue is now resolved: {previousMessage.Message}"); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { var body = $"{updateMessage.Message}"; diff --git a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs index 58276c6fe..5ee380e8b 100644 --- a/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs +++ b/src/NzbDrone.Core/Notifications/Gotify/Gotify.cs @@ -29,6 +29,11 @@ namespace NzbDrone.Core.Notifications.Gotify _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", null); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/INotification.cs b/src/NzbDrone.Core/Notifications/INotification.cs index 1483c1b6f..8431661a6 100644 --- a/src/NzbDrone.Core/Notifications/INotification.cs +++ b/src/NzbDrone.Core/Notifications/INotification.cs @@ -8,10 +8,12 @@ namespace NzbDrone.Core.Notifications void OnGrab(GrabMessage grabMessage); void OnHealthIssue(HealthCheck.HealthCheck healthCheck); + void OnHealthRestored(HealthCheck.HealthCheck previousCheck); void OnApplicationUpdate(ApplicationUpdateMessage updateMessage); void ProcessQueue(); bool SupportsOnGrab { get; } bool SupportsOnHealthIssue { get; } + bool SupportsOnHealthRestored { get; } bool SupportsOnApplicationUpdate { get; } } } diff --git a/src/NzbDrone.Core/Notifications/Join/Join.cs b/src/NzbDrone.Core/Notifications/Join/Join.cs index b8f9320b0..51069d568 100644 --- a/src/NzbDrone.Core/Notifications/Join/Join.cs +++ b/src/NzbDrone.Core/Notifications/Join/Join.cs @@ -27,6 +27,11 @@ namespace NzbDrone.Core.Notifications.Join _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, message.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousMessage) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE_BRANDED, $"The following issue is now resolved: {previousMessage.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE_BRANDED, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Mailgun/Mailgun.cs b/src/NzbDrone.Core/Notifications/Mailgun/Mailgun.cs index 30c5297b4..7eb33c80e 100644 --- a/src/NzbDrone.Core/Notifications/Mailgun/Mailgun.cs +++ b/src/NzbDrone.Core/Notifications/Mailgun/Mailgun.cs @@ -24,6 +24,11 @@ namespace NzbDrone.Core.Notifications.Mailgun _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheckMessage.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheckMessage) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE_BRANDED, $"The following issue is now resolved: {previousCheckMessage.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs b/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs index ba6f3996b..bdf19825e 100644 --- a/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs +++ b/src/NzbDrone.Core/Notifications/Notifiarr/Notifiarr.cs @@ -30,6 +30,11 @@ namespace NzbDrone.Core.Notifications.Notifiarr _proxy.SendNotification(BuildHealthPayload(healthCheck), Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(BuildHealthRestoredPayload(previousCheck), Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(BuildApplicationUploadPayload(updateMessage), Settings); diff --git a/src/NzbDrone.Core/Notifications/NotificationBase.cs b/src/NzbDrone.Core/Notifications/NotificationBase.cs index 2235b4d6d..61af1d21e 100644 --- a/src/NzbDrone.Core/Notifications/NotificationBase.cs +++ b/src/NzbDrone.Core/Notifications/NotificationBase.cs @@ -10,10 +10,12 @@ namespace NzbDrone.Core.Notifications { protected const string RELEASE_GRABBED_TITLE = "Release Grabbed"; protected const string HEALTH_ISSUE_TITLE = "Health Check Failure"; + protected const string HEALTH_RESTORED_TITLE = "Health Check Restored"; protected const string APPLICATION_UPDATE_TITLE = "Application Updated"; protected const string RELEASE_GRABBED_TITLE_BRANDED = "Prowlarr - " + RELEASE_GRABBED_TITLE; protected const string HEALTH_ISSUE_TITLE_BRANDED = "Prowlarr - " + HEALTH_ISSUE_TITLE; + protected const string HEALTH_RESTORED_TITLE_BRANDED = "Prowlarr - " + HEALTH_RESTORED_TITLE; protected const string APPLICATION_UPDATE_TITLE_BRANDED = "Prowlarr - " + APPLICATION_UPDATE_TITLE; public abstract string Name { get; } @@ -37,6 +39,10 @@ namespace NzbDrone.Core.Notifications { } + public virtual void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + } + public virtual void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { } @@ -47,6 +53,7 @@ namespace NzbDrone.Core.Notifications public bool SupportsOnGrab => HasConcreteImplementation("OnGrab"); public bool SupportsOnHealthIssue => HasConcreteImplementation("OnHealthIssue"); + public bool SupportsOnHealthRestored => HasConcreteImplementation("OnHealthRestored"); public bool SupportsOnApplicationUpdate => HasConcreteImplementation("OnApplicationUpdate"); protected TSettings Settings => (TSettings)Definition.Settings; diff --git a/src/NzbDrone.Core/Notifications/NotificationDefinition.cs b/src/NzbDrone.Core/Notifications/NotificationDefinition.cs index f77536f08..67dcefe11 100644 --- a/src/NzbDrone.Core/Notifications/NotificationDefinition.cs +++ b/src/NzbDrone.Core/Notifications/NotificationDefinition.cs @@ -5,14 +5,16 @@ namespace NzbDrone.Core.Notifications public class NotificationDefinition : ProviderDefinition { public bool OnHealthIssue { get; set; } + public bool OnHealthRestored { get; set; } public bool OnApplicationUpdate { get; set; } public bool OnGrab { get; set; } public bool SupportsOnGrab { get; set; } public bool IncludeManualGrabs { get; set; } public bool SupportsOnHealthIssue { get; set; } + public bool SupportsOnHealthRestored { get; set; } public bool IncludeHealthWarnings { get; set; } public bool SupportsOnApplicationUpdate { get; set; } - public override bool Enable => OnHealthIssue || OnApplicationUpdate || OnGrab; + public override bool Enable => OnHealthIssue || OnHealthRestored || OnApplicationUpdate || OnGrab; } } diff --git a/src/NzbDrone.Core/Notifications/NotificationFactory.cs b/src/NzbDrone.Core/Notifications/NotificationFactory.cs index 9fc614811..36dc2145e 100644 --- a/src/NzbDrone.Core/Notifications/NotificationFactory.cs +++ b/src/NzbDrone.Core/Notifications/NotificationFactory.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.Notifications { List<INotification> OnGrabEnabled(); List<INotification> OnHealthIssueEnabled(); + List<INotification> OnHealthRestoredEnabled(); List<INotification> OnApplicationUpdateEnabled(); } @@ -31,6 +32,11 @@ namespace NzbDrone.Core.Notifications return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnHealthIssue).ToList(); } + public List<INotification> OnHealthRestoredEnabled() + { + return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnHealthRestored).ToList(); + } + public List<INotification> OnApplicationUpdateEnabled() { return GetAvailableProviders().Where(n => ((NotificationDefinition)n.Definition).OnApplicationUpdate).ToList(); @@ -42,6 +48,7 @@ namespace NzbDrone.Core.Notifications definition.SupportsOnGrab = provider.SupportsOnGrab; definition.SupportsOnHealthIssue = provider.SupportsOnHealthIssue; + definition.SupportsOnHealthRestored = provider.SupportsOnHealthRestored; definition.SupportsOnApplicationUpdate = provider.SupportsOnApplicationUpdate; } } diff --git a/src/NzbDrone.Core/Notifications/NotificationService.cs b/src/NzbDrone.Core/Notifications/NotificationService.cs index 052f5a69d..33f6e8089 100644 --- a/src/NzbDrone.Core/Notifications/NotificationService.cs +++ b/src/NzbDrone.Core/Notifications/NotificationService.cs @@ -1,10 +1,8 @@ using System; -using System.Drawing.Drawing2D; using NLog; using NzbDrone.Common.Extensions; using NzbDrone.Core.HealthCheck; using NzbDrone.Core.Indexers.Events; -using NzbDrone.Core.Indexers.PassThePopcorn; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Update.History.Events; @@ -13,6 +11,7 @@ namespace NzbDrone.Core.Notifications { public class NotificationService : IHandle<HealthCheckFailedEvent>, + IHandle<HealthCheckRestoredEvent>, IHandleAsync<HealthCheckCompleteEvent>, IHandle<UpdateInstalledEvent>, IHandle<IndexerDownloadEvent> @@ -103,6 +102,29 @@ namespace NzbDrone.Core.Notifications } } + public void Handle(HealthCheckRestoredEvent message) + { + if (message.IsInStartupGracePeriod) + { + return; + } + + foreach (var notification in _notificationFactory.OnHealthRestoredEnabled()) + { + try + { + if (ShouldHandleHealthFailure(message.PreviousCheck, ((NotificationDefinition)notification.Definition).IncludeHealthWarnings)) + { + notification.OnHealthRestored(message.PreviousCheck); + } + } + catch (Exception ex) + { + _logger.Warn(ex, "Unable to send OnHealthRestored notification to: " + notification.Definition.Name); + } + } + } + public void HandleAsync(HealthCheckCompleteEvent message) { ProcessQueue(); diff --git a/src/NzbDrone.Core/Notifications/Ntfy/Ntfy.cs b/src/NzbDrone.Core/Notifications/Ntfy/Ntfy.cs index df81e8140..2c642fd1e 100644 --- a/src/NzbDrone.Core/Notifications/Ntfy/Ntfy.cs +++ b/src/NzbDrone.Core/Notifications/Ntfy/Ntfy.cs @@ -27,6 +27,11 @@ namespace NzbDrone.Core.Notifications.Ntfy _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, message.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE_BRANDED, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE_BRANDED, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs index 417c0fd0b..aa0217548 100644 --- a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs +++ b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs @@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Prowl _prowlProxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousMessage) + { + _prowlProxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousMessage.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _prowlProxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs b/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs index c4fcb46d0..8b4eae918 100644 --- a/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs +++ b/src/NzbDrone.Core/Notifications/PushBullet/PushBullet.cs @@ -29,6 +29,11 @@ namespace NzbDrone.Core.Notifications.PushBullet _proxy.SendNotification(HEALTH_ISSUE_TITLE_BRANDED, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE_BRANDED, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE_BRANDED, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs b/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs index 9d824a35d..28556b77e 100644 --- a/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs +++ b/src/NzbDrone.Core/Notifications/Pushover/Pushover.cs @@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Pushover _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs b/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs index daf44d5e8..98eba8e3f 100644 --- a/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs +++ b/src/NzbDrone.Core/Notifications/SendGrid/SendGrid.cs @@ -29,6 +29,11 @@ namespace NzbDrone.Core.Notifications.SendGrid _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Simplepush/Simplepush.cs b/src/NzbDrone.Core/Notifications/Simplepush/Simplepush.cs index 53b691e72..eaec87f93 100644 --- a/src/NzbDrone.Core/Notifications/Simplepush/Simplepush.cs +++ b/src/NzbDrone.Core/Notifications/Simplepush/Simplepush.cs @@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Simplepush _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Slack/Slack.cs b/src/NzbDrone.Core/Notifications/Slack/Slack.cs index 6737443f5..efb3487d4 100644 --- a/src/NzbDrone.Core/Notifications/Slack/Slack.cs +++ b/src/NzbDrone.Core/Notifications/Slack/Slack.cs @@ -36,6 +36,23 @@ namespace NzbDrone.Core.Notifications.Slack _proxy.SendPayload(payload, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + var attachments = new List<Attachment> + { + new Attachment + { + Title = previousCheck.Source.Name, + Text = $"The following issue is now resolved: {previousCheck.Message}", + Color = "good" + } + }; + + var payload = CreatePayload("Health Issue Resolved", attachments); + + _proxy.SendPayload(payload, Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { var attachments = new List<Attachment> diff --git a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs index 43a0ca283..6cf9b97e0 100644 --- a/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs +++ b/src/NzbDrone.Core/Notifications/Telegram/Telegram.cs @@ -26,6 +26,11 @@ namespace NzbDrone.Core.Notifications.Telegram _proxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendNotification(HEALTH_RESTORED_TITLE, $"The following issue is now resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendNotification(APPLICATION_UPDATE_TITLE, updateMessage.Message, Settings); diff --git a/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs b/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs index 44c13c626..181d1163c 100644 --- a/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs +++ b/src/NzbDrone.Core/Notifications/Twitter/Twitter.cs @@ -29,6 +29,11 @@ namespace NzbDrone.Core.Notifications.Twitter _twitterService.SendNotification($"Health Issue: {healthCheck.Message}", Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _twitterService.SendNotification($"Health Issue Resolved: {previousCheck.Message}", Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _twitterService.SendNotification($"Application Updated: {updateMessage.Message}", Settings); diff --git a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs index c85d9d74d..47d50eb38 100755 --- a/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/Webhook.cs @@ -28,6 +28,11 @@ namespace NzbDrone.Core.Notifications.Webhook _proxy.SendWebhook(BuildHealthPayload(healthCheck), Settings); } + public override void OnHealthRestored(HealthCheck.HealthCheck previousCheck) + { + _proxy.SendWebhook(BuildHealthRestoredPayload(previousCheck), Settings); + } + public override void OnApplicationUpdate(ApplicationUpdateMessage updateMessage) { _proxy.SendWebhook(BuildApplicationUploadPayload(updateMessage), Settings); diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs index 9fc0341df..fabb59e3b 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookBase.cs @@ -46,6 +46,19 @@ namespace NzbDrone.Core.Notifications.Webhook }; } + protected WebhookHealthPayload BuildHealthRestoredPayload(HealthCheck.HealthCheck healthCheck) + { + return new WebhookHealthPayload + { + EventType = WebhookEventType.HealthRestored, + InstanceName = _configFileProvider.InstanceName, + Level = healthCheck.Type, + Message = healthCheck.Message, + Type = healthCheck.Source.Name, + WikiUrl = healthCheck.WikiUrl?.ToString() + }; + } + protected WebhookApplicationUpdatePayload BuildApplicationUploadPayload(ApplicationUpdateMessage updateMessage) { return new WebhookApplicationUpdatePayload diff --git a/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs b/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs index fdc765877..bb6401912 100644 --- a/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs +++ b/src/NzbDrone.Core/Notifications/Webhook/WebhookEventType.cs @@ -13,6 +13,7 @@ namespace NzbDrone.Core.Notifications.Webhook Download, Rename, Health, - ApplicationUpdate + ApplicationUpdate, + HealthRestored } } diff --git a/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs b/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs index 098b9bcdd..1951866ac 100644 --- a/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs +++ b/src/Prowlarr.Api.V1/Notifications/NotificationResource.cs @@ -7,10 +7,12 @@ namespace Prowlarr.Api.V1.Notifications public string Link { get; set; } public bool OnGrab { get; set; } public bool OnHealthIssue { get; set; } + public bool OnHealthRestored { get; set; } public bool OnApplicationUpdate { get; set; } public bool SupportsOnGrab { get; set; } public bool IncludeManualGrabs { get; set; } public bool SupportsOnHealthIssue { get; set; } + public bool SupportsOnHealthRestored { get; set; } public bool IncludeHealthWarnings { get; set; } public bool SupportsOnApplicationUpdate { get; set; } public string TestCommand { get; set; } @@ -31,7 +33,9 @@ namespace Prowlarr.Api.V1.Notifications resource.SupportsOnGrab = definition.SupportsOnGrab; resource.IncludeManualGrabs = definition.IncludeManualGrabs; resource.OnHealthIssue = definition.OnHealthIssue; + resource.OnHealthRestored = definition.OnHealthRestored; resource.SupportsOnHealthIssue = definition.SupportsOnHealthIssue; + resource.SupportsOnHealthRestored = definition.SupportsOnHealthRestored; resource.IncludeHealthWarnings = definition.IncludeHealthWarnings; resource.OnApplicationUpdate = definition.OnApplicationUpdate; resource.SupportsOnApplicationUpdate = definition.SupportsOnApplicationUpdate; @@ -52,7 +56,9 @@ namespace Prowlarr.Api.V1.Notifications definition.SupportsOnGrab = resource.SupportsOnGrab; definition.IncludeManualGrabs = resource.IncludeManualGrabs; definition.OnHealthIssue = resource.OnHealthIssue; + definition.OnHealthRestored = resource.OnHealthRestored; definition.SupportsOnHealthIssue = resource.SupportsOnHealthIssue; + definition.SupportsOnHealthRestored = resource.SupportsOnHealthRestored; definition.IncludeHealthWarnings = resource.IncludeHealthWarnings; definition.OnApplicationUpdate = resource.OnApplicationUpdate; definition.SupportsOnApplicationUpdate = resource.SupportsOnApplicationUpdate;