diff --git a/src/NzbDrone.Core/Download/Clients/DownloadClientException.cs b/src/NzbDrone.Core/Download/Clients/DownloadClientException.cs index 2b8a8674a..9598e04ef 100644 --- a/src/NzbDrone.Core/Download/Clients/DownloadClientException.cs +++ b/src/NzbDrone.Core/Download/Clients/DownloadClientException.cs @@ -1,14 +1,30 @@ -using NzbDrone.Common.Exceptions; +using System; +using NzbDrone.Common.Exceptions; namespace NzbDrone.Core.Download.Clients { public class DownloadClientException : NzbDroneException { - public DownloadClientException(string message, params object[] args) : base(message, args) + public DownloadClientException(string message, params object[] args) + : base(string.Format(message, args)) { + } - public DownloadClientException(string message) : base(message) + public DownloadClientException(string message) + : base(message) + { + + } + + public DownloadClientException(string message, Exception innerException, params object[] args) + : base(string.Format(message, args), innerException) + { + + } + + public DownloadClientException(string message, Exception innerException) + : base(message, innerException) { } } diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs index 4df64d48a..c670fffb1 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/Nzbget.cs @@ -11,6 +11,7 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.Indexers; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.Download.Clients.Nzbget { @@ -290,10 +291,8 @@ namespace NzbDrone.Core.Download.Clients.Nzbget } } - public override ValidationResult Test() + protected override void Test(List failures) { - var failures = new List(); - failures.AddIfNotNull(TestConnection()); failures.AddIfNotNull(TestCategory()); @@ -301,8 +300,6 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { failures.AddIfNotNull(TestFolder(Settings.TvCategoryLocalPath, "TvCategoryLocalPath")); } - - return new ValidationResult(failures); } private ValidationFailure TestConnection() @@ -313,6 +310,10 @@ namespace NzbDrone.Core.Download.Clients.Nzbget } catch (Exception ex) { + if (ex.Message.ContainsIgnoreCase("Authentication failed")) + { + return new ValidationFailure("Username", "Authentication failed"); + } _logger.ErrorException(ex.Message, ex); return new ValidationFailure("Host", "Unable to connect to NZBGet"); } @@ -327,7 +328,11 @@ namespace NzbDrone.Core.Download.Clients.Nzbget if (!Settings.TvCategory.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == Settings.TvCategory)) { - return new ValidationFailure("TvCategory", "Category does not exist"); + return new NzbDroneValidationFailure("TvCategory", "Category does not exist") + { + InfoLink = String.Format("http://{0}:{1}/", Settings.Host, Settings.Port), + DetailedDescription = "The Category your entered doesn't exist in NzbGet. Go to NzbGet to create it." + }; } return null; diff --git a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs index 6f7f50a6f..66c400192 100644 --- a/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProxy.cs @@ -193,7 +193,12 @@ namespace NzbDrone.Core.Download.Clients.Nzbget { if (response.ResponseStatus != ResponseStatus.Completed) { - throw new DownloadClientException("Unable to connect to NzbGet, please check your settings"); + throw new DownloadClientException("Unable to connect to NzbGet, please check your settings", response.ErrorException); + } + + if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized) + { + throw new DownloadClientException("Authentication failed for NzbGet, please check your settings", response.ErrorException); } var result = Json.Deserialize(response.Content); diff --git a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs index 14424576d..8bf52fe95 100644 --- a/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs +++ b/src/NzbDrone.Core/Download/Clients/Pneumatic/Pneumatic.cs @@ -95,13 +95,9 @@ namespace NzbDrone.Core.Download.Clients.Pneumatic return status; } - public override ValidationResult Test() + protected override void Test(List failures) { - var failures = new List(); - failures.AddIfNotNull(TestWrite(Settings.NzbFolder, "NzbFolder")); - - return new ValidationResult(failures); } private ValidationFailure TestWrite(String folder, String propertyName) diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs index 420deced7..43e383b98 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/Sabnzbd.cs @@ -303,19 +303,16 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd return status; } - public override ValidationResult Test() + protected override void Test(List failures) { - var failures = new List(); - failures.AddIfNotNull(TestConnection()); + failures.AddIfNotNull(TestAuthentication()); failures.AddIfNotNull(TestCategory()); if (!Settings.TvCategoryLocalPath.IsNullOrWhiteSpace()) { failures.AddIfNotNull(TestFolder(Settings.TvCategoryLocalPath, "TvCategoryLocalPath")); } - - return new ValidationResult(failures); } private ValidationFailure TestConnection() @@ -333,6 +330,28 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd return null; } + private ValidationFailure TestAuthentication() + { + try + { + _proxy.GetConfig(Settings); + } + catch (Exception ex) + { + if (ex.Message.ContainsIgnoreCase("API Key Incorrect")) + { + return new ValidationFailure("APIKey", "API Key Incorrect"); + } + if (ex.Message.ContainsIgnoreCase("API Key Required")) + { + return new ValidationFailure("APIKey", "API Key Required"); + } + throw; + } + + return null; + } + private ValidationFailure TestCategory() { var config = this._proxy.GetConfig(Settings); diff --git a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs index 90acd4cd6..8f7a40e5d 100644 --- a/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs +++ b/src/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdProxy.cs @@ -145,7 +145,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd { if (response.ResponseStatus != ResponseStatus.Completed) { - throw new DownloadClientException("Unable to connect to SABnzbd, please check your settings"); + throw new DownloadClientException("Unable to connect to SABnzbd, please check your settings", response.ErrorException); } SabnzbdJsonError result; diff --git a/src/NzbDrone.Core/Download/Clients/UsenetBlackhole/UsenetBlackhole.cs b/src/NzbDrone.Core/Download/Clients/UsenetBlackhole/UsenetBlackhole.cs index 442be58e9..421991974 100644 --- a/src/NzbDrone.Core/Download/Clients/UsenetBlackhole/UsenetBlackhole.cs +++ b/src/NzbDrone.Core/Download/Clients/UsenetBlackhole/UsenetBlackhole.cs @@ -143,14 +143,10 @@ namespace NzbDrone.Core.Download.Clients.UsenetBlackhole }; } - public override ValidationResult Test() + protected override void Test(List failures) { - var failures = new List(); - failures.AddIfNotNull(TestFolder(Settings.NzbFolder, "NzbFolder")); failures.AddIfNotNull(TestFolder(Settings.WatchFolder, "WatchFolder")); - - return new ValidationResult(failures); } } } diff --git a/src/NzbDrone.Core/Download/DownloadClientBase.cs b/src/NzbDrone.Core/Download/DownloadClientBase.cs index 7ff6d4c13..1f84b1ff0 100644 --- a/src/NzbDrone.Core/Download/DownloadClientBase.cs +++ b/src/NzbDrone.Core/Download/DownloadClientBase.cs @@ -11,6 +11,7 @@ using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Configuration; using NLog; using FluentValidation.Results; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.Download { @@ -39,7 +40,6 @@ namespace NzbDrone.Core.Download } public ProviderDefinition Definition { get; set; } - public abstract ValidationResult Test(); protected TSettings Settings { @@ -101,11 +101,33 @@ namespace NzbDrone.Core.Download } } + public ValidationResult Test() + { + var failures = new List(); + + try + { + Test(failures); + } + catch (Exception ex) + { + _logger.ErrorException("Test aborted due to exception", ex); + failures.Add(new ValidationFailure(string.Empty, "Test was aborted due to an error: " + ex.Message)); + } + + return new ValidationResult(failures); + } + + protected abstract void Test(List failures); + protected ValidationFailure TestFolder(String folder, String propertyName, Boolean mustBeWritable = true) { if (!_diskProvider.FolderExists(folder)) { - return new ValidationFailure(propertyName, "Folder does not exist"); + return new NzbDroneValidationFailure(propertyName, "Folder does not exist") + { + DetailedDescription = "The folder you specified does not exist or is inaccessible. Please verify the folder permissions for the user account that is used to execute NzbDrone." + }; } if (mustBeWritable) @@ -119,7 +141,10 @@ namespace NzbDrone.Core.Download catch (Exception ex) { _logger.ErrorException(ex.Message, ex); - return new ValidationFailure(propertyName, "Unable to write to folder"); + return new NzbDroneValidationFailure(propertyName, "Unable to write to folder") + { + DetailedDescription = "The folder you specified is not writable. Please verify the folder permissions for the user account that is used to execute NzbDrone." + }; } }