From 7a1fa71b7670c9e76a6381cead1b6bd45405f85f Mon Sep 17 00:00:00 2001 From: Qstick Date: Sun, 29 Mar 2020 21:23:48 -0400 Subject: [PATCH] New: Add back Prowl Notifications --- .../Migration/157_remove_growl_prowl.cs | 4 +- .../Notifications/Prowl/Prowl.cs | 43 +++++++++++ .../Notifications/Prowl/ProwlException.cs | 18 +++++ .../Notifications/Prowl/ProwlPriority.cs | 11 +++ .../Notifications/Prowl/ProwlProxy.cs | 74 +++++++++++++++++++ .../Notifications/Prowl/ProwlSettings.cs | 33 +++++++++ 6 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core/Notifications/Prowl/Prowl.cs create mode 100644 src/NzbDrone.Core/Notifications/Prowl/ProwlException.cs create mode 100644 src/NzbDrone.Core/Notifications/Prowl/ProwlPriority.cs create mode 100644 src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs create mode 100644 src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs diff --git a/src/NzbDrone.Core/Datastore/Migration/157_remove_growl_prowl.cs b/src/NzbDrone.Core/Datastore/Migration/157_remove_growl_prowl.cs index 24612c12f..b62a4f6e1 100644 --- a/src/NzbDrone.Core/Datastore/Migration/157_remove_growl_prowl.cs +++ b/src/NzbDrone.Core/Datastore/Migration/157_remove_growl_prowl.cs @@ -9,7 +9,9 @@ namespace NzbDrone.Core.Datastore.Migration protected override void MainDbUpgrade() { Delete.FromTable("Notifications").Row(new { Implementation = "Growl" }); - Delete.FromTable("Notifications").Row(new { Implementation = "Prowl" }); + + // Prowl Added back + // Delete.FromTable("Notifications").Row(new { Implementation = "Prowl" }); } } } diff --git a/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs new file mode 100644 index 000000000..279db9770 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Prowl/Prowl.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using FluentValidation.Results; +using NzbDrone.Common.Extensions; + +namespace NzbDrone.Core.Notifications.Prowl +{ + public class Prowl : NotificationBase + { + private readonly IProwlProxy _prowlProxy; + + public Prowl(IProwlProxy prowlProxy) + { + _prowlProxy = prowlProxy; + } + + public override string Link => "https://www.prowlapp.com/"; + public override string Name => "Prowl"; + + public override void OnGrab(GrabMessage grabMessage) + { + _prowlProxy.SendNotification(MOVIE_GRABBED_TITLE, grabMessage.Message, Settings.ApiKey, (ProwlPriority)Settings.Priority); + } + + public override void OnDownload(DownloadMessage message) + { + _prowlProxy.SendNotification(MOVIE_DOWNLOADED_TITLE, message.Message, Settings.ApiKey, (ProwlPriority)Settings.Priority); + } + + public override void OnHealthIssue(HealthCheck.HealthCheck healthCheck) + { + _prowlProxy.SendNotification(HEALTH_ISSUE_TITLE, healthCheck.Message, Settings.ApiKey, (ProwlPriority)Settings.Priority); + } + + public override ValidationResult Test() + { + var failures = new List(); + + failures.AddIfNotNull(_prowlProxy.Test(Settings)); + + return new ValidationResult(failures); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlException.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlException.cs new file mode 100644 index 000000000..ee1a61df4 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlException.cs @@ -0,0 +1,18 @@ +using System; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Notifications.Prowl +{ + public class ProwlException : NzbDroneException + { + public ProwlException(string message) + : base(message) + { + } + + public ProwlException(string message, Exception innerException, params object[] args) + : base(message, innerException, args) + { + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlPriority.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlPriority.cs new file mode 100644 index 000000000..ef62f143f --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlPriority.cs @@ -0,0 +1,11 @@ +namespace NzbDrone.Core.Notifications.Prowl +{ + public enum ProwlPriority + { + VeryLow = -2, + Low = -1, + Normal = 0, + High = 1, + Emergency = 2 + } +} diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs new file mode 100644 index 000000000..5998acc78 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlProxy.cs @@ -0,0 +1,74 @@ +using System; +using System.Net; +using FluentValidation.Results; +using NLog; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Rest; +using RestSharp; + +namespace NzbDrone.Core.Notifications.Prowl +{ + public interface IProwlProxy + { + void SendNotification(string title, string message, string apiKey, ProwlPriority priority = ProwlPriority.Normal, string url = null); + ValidationFailure Test(ProwlSettings settings); + } + + public class ProwlProxy : IProwlProxy + { + private const string PUSH_URL = "https://api.prowlapp.com/publicapi/add"; + private readonly IRestClientFactory _restClientFactory; + private readonly Logger _logger; + + public ProwlProxy(IRestClientFactory restClientFactory, Logger logger) + { + _restClientFactory = restClientFactory; + _logger = logger; + } + + public void SendNotification(string title, string message, string apiKey, ProwlPriority priority = ProwlPriority.Normal, string url = null) + { + try + { + var client = _restClientFactory.BuildClient(PUSH_URL); + var request = new RestRequest(Method.POST); + + request.AddParameter("apikey", apiKey); + request.AddParameter("application", BuildInfo.AppName); + request.AddParameter("event", title); + request.AddParameter("description", message); + request.AddParameter("priority", priority); + request.AddParameter("url", url); + + client.ExecuteAndValidate(request); + } + catch (RestException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) + { + _logger.Error(ex, "Apikey is invalid: {0}", apiKey); + throw new ProwlException("Apikey is invalid", ex); + } + + throw new ProwlException("Unable to send text message: " + ex.Message, ex); + } + } + + public ValidationFailure Test(ProwlSettings settings) + { + try + { + const string title = "Test Notification"; + const string body = "This is a test message from Radarr"; + + SendNotification(title, body, settings.ApiKey); + } + catch (Exception ex) + { + return new ValidationFailure("ApiKey", ex.Message); + } + + return null; + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs b/src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs new file mode 100644 index 000000000..7bcda63a3 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Prowl/ProwlSettings.cs @@ -0,0 +1,33 @@ +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Notifications.Prowl +{ + public class ProwlSettingsValidator : AbstractValidator + { + public ProwlSettingsValidator() + { + RuleFor(c => c.ApiKey).NotEmpty(); + } + } + + public class ProwlSettings : IProviderConfig + { + private static readonly ProwlSettingsValidator Validator = new ProwlSettingsValidator(); + + [FieldDefinition(0, Label = "API Key", HelpLink = "https://www.prowlapp.com/api_settings.php")] + public string ApiKey { get; set; } + + [FieldDefinition(1, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(ProwlPriority))] + public int Priority { get; set; } + + public bool IsValid => !string.IsNullOrWhiteSpace(ApiKey) && Priority >= -2 && Priority <= 2; + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +}