diff --git a/NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs b/NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs index 47d79c849..ebc49505f 100644 --- a/NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs +++ b/NzbDrone.Api/ErrorManagement/NzbDroneErrorPipeline.cs @@ -4,6 +4,7 @@ using NLog; using Nancy; using NzbDrone.Api.Extensions; using NzbDrone.Core; +using NzbDrone.Core.Exceptions; using HttpStatusCode = Nancy.HttpStatusCode; namespace NzbDrone.Api.ErrorManagement diff --git a/NzbDrone.Core/Exceptions/BadRequestException.cs b/NzbDrone.Core/Exceptions/BadRequestException.cs new file mode 100644 index 000000000..07d23d263 --- /dev/null +++ b/NzbDrone.Core/Exceptions/BadRequestException.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Exceptions +{ + public class BadRequestException : DownstreamException + { + public BadRequestException(HttpStatusCode statusCode, string message) : base(statusCode, message) + { + } + + public BadRequestException(HttpStatusCode statusCode, string message, params object[] args) : base(statusCode, message, args) + { + } + } +} diff --git a/NzbDrone.Core/Exceptions/DownstreamException.cs b/NzbDrone.Core/Exceptions/DownstreamException.cs new file mode 100644 index 000000000..0ce8f1a94 --- /dev/null +++ b/NzbDrone.Core/Exceptions/DownstreamException.cs @@ -0,0 +1,21 @@ +using System.Net; +using NzbDrone.Common.Exceptions; + +namespace NzbDrone.Core.Exceptions +{ + public class DownstreamException : NzbDroneException + { + public HttpStatusCode StatusCode { get; private set; } + + public DownstreamException(HttpStatusCode statusCode, string message, params object[] args) : base(message, args) + { + StatusCode = statusCode; + } + + public DownstreamException(HttpStatusCode statusCode, string message) + : base(message) + { + StatusCode = statusCode; + } + } +} diff --git a/NzbDrone.Core/NzbDroneClientException.cs b/NzbDrone.Core/Exceptions/NzbDroneClientException.cs similarity index 93% rename from NzbDrone.Core/NzbDroneClientException.cs rename to NzbDrone.Core/Exceptions/NzbDroneClientException.cs index cc94caffc..d9225eb2c 100644 --- a/NzbDrone.Core/NzbDroneClientException.cs +++ b/NzbDrone.Core/Exceptions/NzbDroneClientException.cs @@ -1,7 +1,7 @@ using System.Net; using NzbDrone.Common.Exceptions; -namespace NzbDrone.Core +namespace NzbDrone.Core.Exceptions { public class NzbDroneClientException : NzbDroneException { diff --git a/NzbDrone.Core/Exceptions/StatusCodeToExceptions.cs b/NzbDrone.Core/Exceptions/StatusCodeToExceptions.cs new file mode 100644 index 000000000..ab394a9a6 --- /dev/null +++ b/NzbDrone.Core/Exceptions/StatusCodeToExceptions.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; + +namespace NzbDrone.Core.Exceptions +{ + public static class StatusCodeToExceptions + { + public static void VerifyStatusCode(this HttpStatusCode statusCode, string message = null) + { + if (String.IsNullOrEmpty(message)) + { + message = statusCode.ToString(); + } + + switch (statusCode) + { + case HttpStatusCode.BadRequest: + throw new BadRequestException(statusCode, message); + + case HttpStatusCode.Unauthorized: + throw new UnauthorizedAccessException(message); + + case HttpStatusCode.PaymentRequired: + throw new DownstreamException(statusCode, message); + + case HttpStatusCode.InternalServerError: + throw new DownstreamException(statusCode, message); + } + } + } +} diff --git a/NzbDrone.Core/MetadataSource/Trakt/TraktException.cs b/NzbDrone.Core/MetadataSource/Trakt/TraktException.cs index 999122301..3d51fe8ab 100644 --- a/NzbDrone.Core/MetadataSource/Trakt/TraktException.cs +++ b/NzbDrone.Core/MetadataSource/Trakt/TraktException.cs @@ -1,4 +1,5 @@ using System.Net; +using NzbDrone.Core.Exceptions; namespace NzbDrone.Core.MetadataSource.Trakt { diff --git a/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroid.cs b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroid.cs new file mode 100644 index 000000000..22f4656f7 --- /dev/null +++ b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroid.cs @@ -0,0 +1,47 @@ +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Notifications.NotifyMyAndroid +{ + public class NotifyMyAndroid : NotificationBase + { + private readonly INotifyMyAndroidProxy _notifyMyAndroidProxy; + + public NotifyMyAndroid(INotifyMyAndroidProxy notifyMyAndroidProxy) + { + _notifyMyAndroidProxy = notifyMyAndroidProxy; + } + + public override string Name + { + get { return "NotifyMyAndroid"; } + } + + public override string ImplementationName + { + get { return "NotifyMyAndroid"; } + } + + public override string Link + { + get { return "http://www.notifymyandroid.com/"; } + } + + public override void OnGrab(string message) + { + const string title = "Episode Grabbed"; + + _notifyMyAndroidProxy.SendNotification(title, message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority); + } + + public override void OnDownload(string message, Series series) + { + const string title = "Episode Downloaded"; + + _notifyMyAndroidProxy.SendNotification(title, message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority); + } + + public override void AfterRename(Series series) + { + } + } +} diff --git a/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidPriority.cs b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidPriority.cs new file mode 100644 index 000000000..fd91e91d5 --- /dev/null +++ b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidPriority.cs @@ -0,0 +1,11 @@ +namespace NzbDrone.Core.Notifications.NotifyMyAndroid +{ + public enum NotifyMyAndroidPriority + { + VeryLow = -2, + Moderate = -1, + Normal = 0, + High = 1, + Emergency = 2 + } +} diff --git a/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs new file mode 100644 index 000000000..170bf8522 --- /dev/null +++ b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs @@ -0,0 +1,69 @@ +using System; +using System.Linq; +using System.Net; +using System.Xml.Linq; +using NLog.LayoutRenderers; +using NzbDrone.Core.Exceptions; +using NzbDrone.Core.Messaging; +using NzbDrone.Core.Messaging.Commands; +using RestSharp; +using NzbDrone.Core.Rest; + +namespace NzbDrone.Core.Notifications.NotifyMyAndroid +{ + public interface INotifyMyAndroidProxy + { + void SendNotification(string title, string message, string apiKye, NotifyMyAndroidPriority priority); + } + + public class NotifyMyAndroidProxy : INotifyMyAndroidProxy, IExecute + { + private const string URL = "https://www.notifymyandroid.com/publicapi"; + + public void SendNotification(string title, string message, string apiKey, NotifyMyAndroidPriority priority) + { + var client = new RestClient(URL); + var request = new RestRequest("notify", Method.POST); + request.RequestFormat = DataFormat.Xml; + request.AddParameter("apikey", apiKey); + request.AddParameter("application", "NzbDrone"); + request.AddParameter("event", title); + request.AddParameter("description", message); + request.AddParameter("priority", (int)priority); + + var response = client.ExecuteAndValidate(request); + ValidateResponse(response); + } + + private void Verify(string apiKey) + { + var client = new RestClient(URL); + var request = new RestRequest("verify", Method.GET); + request.RequestFormat = DataFormat.Xml; + request.AddParameter("apikey", apiKey, ParameterType.GetOrPost); + + var response = client.ExecuteAndValidate(request); + ValidateResponse(response); + } + + private void ValidateResponse(IRestResponse response) + { + var xDoc = XDocument.Parse(response.Content); + var nma = xDoc.Descendants("nma").Single(); + var error = nma.Descendants("error").SingleOrDefault(); + + if (error != null) + { + ((HttpStatusCode)Convert.ToInt32(error.Attribute("code").Value)).VerifyStatusCode(error.Value); + } + } + + public void Execute(TestNotifyMyAndroidCommand message) + { + const string title = "Test Notification"; + const string body = "This is a test message from NzbDrone"; + Verify(message.ApiKey); + SendNotification(title, body, message.ApiKey, (NotifyMyAndroidPriority)message.Priority); + } + } +} diff --git a/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidSettings.cs b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidSettings.cs new file mode 100644 index 000000000..c8c941239 --- /dev/null +++ b/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidSettings.cs @@ -0,0 +1,22 @@ +using System; +using NzbDrone.Core.Annotations; + +namespace NzbDrone.Core.Notifications.NotifyMyAndroid +{ + public class NotifyMyAndroidSettings : INotifcationSettings + { + [FieldDefinition(0, Label = "API Key", HelpLink = "http://www.notifymyandroid.com/")] + public String ApiKey { get; set; } + + [FieldDefinition(1, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(NotifyMyAndroidPriority))] + public Int32 Priority { get; set; } + + public bool IsValid + { + get + { + return !String.IsNullOrWhiteSpace(ApiKey) && Priority != null & Priority >= -1 && Priority <= 2; + } + } + } +} diff --git a/NzbDrone.Core/Notifications/NotifyMyAndroid/TestNotifyMyAndroidCommand.cs b/NzbDrone.Core/Notifications/NotifyMyAndroid/TestNotifyMyAndroidCommand.cs new file mode 100644 index 000000000..bb93b8fdd --- /dev/null +++ b/NzbDrone.Core/Notifications/NotifyMyAndroid/TestNotifyMyAndroidCommand.cs @@ -0,0 +1,18 @@ +using NzbDrone.Core.Messaging.Commands; + +namespace NzbDrone.Core.Notifications.NotifyMyAndroid +{ + public class TestNotifyMyAndroidCommand : Command + { + + public override bool SendUpdatesToClient + { + get + { + return true; + } + } + public string ApiKey { get; set; } + public int Priority { get; set; } + } +} diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index dae681ba9..acb50ac6d 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -210,6 +210,10 @@ + + + + @@ -245,7 +249,11 @@ - + + + + +