diff --git a/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs new file mode 100644 index 000000000..ef7de07a1 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Boxcar/Boxcar.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using FluentValidation.Results; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Notifications.Boxcar +{ + public class Boxcar : NotificationBase + { + private readonly IBoxcarProxy _proxy; + + public Boxcar(IBoxcarProxy proxy) + { + _proxy = proxy; + } + + public override string Link + { + get { return "https://boxcar.io/client"; } + } + + public override void OnGrab(string message) + { + const string title = "Episode Grabbed"; + + _proxy.SendNotification(title, message, Settings); + } + + public override void OnDownload(DownloadMessage message) + { + const string title = "Episode Downloaded"; + + _proxy.SendNotification(title, message.Message, Settings); + } + + public override void OnRename(Series series) + { + } + + public override string Name + { + get + { + return "Boxcar"; + } + } + + public override bool SupportsOnRename + { + get + { + return false; + } + } + + public override ValidationResult Test() + { + var failures = new List(); + + failures.AddIfNotNull(_proxy.Test(Settings)); + + return new ValidationResult(failures); + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarException.cs b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarException.cs new file mode 100644 index 000000000..139c3b1ab --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarException.cs @@ -0,0 +1,16 @@ +using System; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Notifications.Boxcar +{ + public class BoxcarException : NzbDroneException + { + public BoxcarException(string message) : base(message) + { + } + + public BoxcarException(string message, Exception innerException, params object[] args) : base(message, innerException, args) + { + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs new file mode 100644 index 000000000..f6b626025 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarProxy.cs @@ -0,0 +1,95 @@ +using System; +using System.Linq; +using System.Net; +using FluentValidation.Results; +using NLog; +using RestSharp; +using NzbDrone.Core.Rest; + +namespace NzbDrone.Core.Notifications.Boxcar +{ + public interface IBoxcarProxy + { + void SendNotification(string title, string message, BoxcarSettings settings); + ValidationFailure Test(BoxcarSettings settings); + } + + public class BoxcarProxy : IBoxcarProxy + { + private readonly Logger _logger; + private const string URL = "https://new.boxcar.io/api/notifications"; + + public BoxcarProxy(Logger logger) + { + _logger = logger; + } + + public void SendNotification(string title, string message, BoxcarSettings settings) + { + var request = new RestRequest(Method.POST); + + try + { + SendNotification(title, message, request, settings); + } + catch (BoxcarException ex) + { + _logger.ErrorException("Unable to send message", ex); + throw new BoxcarException("Unable to send Boxcar notifications"); + } + } + + public ValidationFailure Test(BoxcarSettings settings) + { + try + { + const string title = "Test Notification"; + const string body = "This is a test message from Sonarr"; + + SendNotification(title, body, settings); + return null; + } + catch (RestException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) + { + _logger.ErrorException("Access Token is invalid: " + ex.Message, ex); + return new ValidationFailure("Token", "Access Token is invalid"); + } + + _logger.ErrorException("Unable to send test message: " + ex.Message, ex); + return new ValidationFailure("Token", "Unable to send test message"); + } + catch (Exception ex) + { + _logger.ErrorException("Unable to send test message: " + ex.Message, ex); + return new ValidationFailure("", "Unable to send test message"); + } + } + + private void SendNotification(string title, string message, RestRequest request, BoxcarSettings settings) + { + try + { + var client = RestClientFactory.BuildClient(URL); + + request.AddParameter("user_credentials", settings.Token); + request.AddParameter("notification[title]", title); + request.AddParameter("notification[long_message]", message); + request.AddParameter("notification[source_name]", "Sonarr"); + + client.ExecuteAndValidate(request); + } + catch (RestException ex) + { + if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) + { + _logger.ErrorException("Access Token is invalid: " + ex.Message, ex); + throw; + } + + throw new BoxcarException("Unable to send text message: " + ex.Message, ex); + } + } + } +} diff --git a/src/NzbDrone.Core/Notifications/Boxcar/BoxcarSettings.cs b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarSettings.cs new file mode 100644 index 000000000..352f15312 --- /dev/null +++ b/src/NzbDrone.Core/Notifications/Boxcar/BoxcarSettings.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using FluentValidation; +using NzbDrone.Core.Annotations; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.Validation; + +namespace NzbDrone.Core.Notifications.Boxcar +{ + public class BoxcarSettingsValidator : AbstractValidator + { + public BoxcarSettingsValidator() + { + RuleFor(c => c.Token).NotEmpty(); + } + } + + public class BoxcarSettings : IProviderConfig + { + private static readonly BoxcarSettingsValidator Validator = new BoxcarSettingsValidator(); + + [FieldDefinition(0, Label = "Access Token", HelpText = "Your Access Token, from your Boxcar account settings: https://new.boxcar.io/account/edit", HelpLink = "https://new.boxcar.io/account/edit")] + public string Token { get; set; } + + public NzbDroneValidationResult Validate() + { + return new NzbDroneValidationResult(Validator.Validate(this)); + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index a1fe7661c..b522680b0 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -719,6 +719,10 @@ + + + + diff --git a/src/NzbDrone.Core/Rest/RestSharpExtensions.cs b/src/NzbDrone.Core/Rest/RestSharpExtensions.cs index 37958317f..b09314d49 100644 --- a/src/NzbDrone.Core/Rest/RestSharpExtensions.cs +++ b/src/NzbDrone.Core/Rest/RestSharpExtensions.cs @@ -43,6 +43,10 @@ namespace NzbDrone.Core.Rest { return response; } + case HttpStatusCode.Created: + { + return response; + } default: { Logger.Warn("[{0}] [{1}] Failed. [{2}]", response.Request.Method, response.ResponseUri.ToString(), response.StatusCode);