Fixed: (Apps) Ensure validation for test connection

pull/1754/head
Bogdan 1 year ago
parent e0e1b1494e
commit 6880e67507

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
@ -32,10 +31,10 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
{
failures.AddIfNotNull(_lazyLibrarianV1Proxy.TestConnection(Settings));
}
catch (WebException ex)
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to LazyLibrarian"));
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to LazyLibrarian. {ex.Message}"));
}
return new ValidationResult(failures);

@ -44,7 +44,7 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
[FieldDefinition(1, Label = "LazyLibrarian Server", HelpText = "URL used to connect to LazyLibrarian server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:5299")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by LazyLibrarian in Settings/Web Interface")]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by LazyLibrarian in Settings/Web Interface")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using FluentValidation.Results;
using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.Applications.LazyLibrarian
{
@ -139,11 +139,11 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
return new ValidationFailure("ApiKey", status.Error.Message);
}
var indexers = GetIndexers(settings);
GetIndexers(settings);
}
catch (HttpException ex)
{
_logger.Error(ex, "Unable to send test message");
_logger.Error(ex, "Unable to complete application test");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (LazyLibrarianException ex)
@ -153,8 +153,8 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
_logger.Error(ex, "Unable to complete application test");
return new ValidationFailure("", $"Unable to send test message. {ex.Message}");
}
return null;
@ -164,7 +164,9 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
{
var baseUrl = settings.BaseUrl.TrimEnd('/');
var requestBuilder = new HttpRequestBuilder(baseUrl).Resource(resource)
var requestBuilder = new HttpRequestBuilder(baseUrl)
.Resource(resource)
.Accept(HttpAccept.Json)
.AddQueryParam("cmd", command)
.AddQueryParam("apikey", settings.ApiKey);
@ -191,9 +193,12 @@ namespace NzbDrone.Core.Applications.LazyLibrarian
{
var response = _httpClient.Execute(request);
var results = JsonConvert.DeserializeObject<TResource>(response.Content);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
return results;
return Json.Deserialize<TResource>(response.Content);
}
private int CalculatePriority(int indexerPriority) => ProwlarrHighestPriority - indexerPriority + 1;

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
@ -48,9 +51,36 @@ namespace NzbDrone.Core.Applications.Lidarr
{
failures.AddIfNotNull(_lidarrV1Proxy.TestConnection(BuildLidarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
switch (ex.Response.StatusCode)
{
case HttpStatusCode.Unauthorized:
_logger.Error(ex, "API Key is invalid");
failures.AddIfNotNull(new ValidationFailure("ApiKey", "API Key is invalid"));
break;
case HttpStatusCode.BadRequest:
_logger.Error(ex, "Prowlarr URL is invalid");
failures.AddIfNotNull(new ValidationFailure("ProwlarrUrl", "Prowlarr URL is invalid, Lidarr cannot connect to Prowlarr"));
break;
case HttpStatusCode.SeeOther:
_logger.Error(ex, "Lidarr returned redirect and is invalid");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Lidarr URL is invalid, Prowlarr cannot connect to Lidarr - are you missing a URL base?"));
break;
default:
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Lidarr. {ex.Message}"));
break;
}
}
catch (JsonReaderException ex)
{
_logger.Error(ex, "Unable to parse JSON response from application");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to parse JSON response from application. {ex.Message}"));
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Lidarr. {ex.Message}"));
}

@ -33,7 +33,7 @@ namespace NzbDrone.Core.Applications.Lidarr
[FieldDefinition(1, Label = "Lidarr Server", HelpText = "URL used to connect to Lidarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8686")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Lidarr in Settings/General")]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Lidarr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]

@ -91,6 +91,8 @@ namespace NzbDrone.Core.Applications.Lidarr
}
catch (HttpException ex) when (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Debug("Retrying to add indexer forcefully");
request.Url = request.Url.AddQueryParam("forceSave", "true");
return ExecuteIndexerRequest(request);
@ -113,47 +115,16 @@ namespace NzbDrone.Core.Applications.Lidarr
request.SetContent(indexer.ToJson());
try
{
var applicationVersion = _httpClient.Post<LidarrIndexer>(request).Headers.GetSingleValue("X-Application-Version");
if (applicationVersion == null)
{
return new ValidationFailure(string.Empty, "Failed to fetch Lidarr version");
}
var applicationVersion = _httpClient.Post(request).Headers.GetSingleValue("X-Application-Version");
if (new Version(applicationVersion) < MinimumApplicationVersion)
{
return new ValidationFailure(string.Empty, $"Lidarr version should be at least {MinimumApplicationVersion.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
}
catch (HttpException ex)
if (applicationVersion == null)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Error(ex, "API Key is invalid");
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Lidarr cannot connect to Prowlarr");
}
if (ex.Response.StatusCode == HttpStatusCode.SeeOther)
{
_logger.Error(ex, "Lidarr returned redirect and is invalid");
return new ValidationFailure("BaseUrl", "Lidarr url is invalid, Prowlarr cannot connect to Lidarr - are you missing a url base?");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
return new ValidationFailure(string.Empty, "Failed to fetch Lidarr version");
}
catch (Exception ex)
if (new Version(applicationVersion) < MinimumApplicationVersion)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
return new ValidationFailure(string.Empty, $"Lidarr version should be at least {MinimumApplicationVersion.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
return null;
@ -210,7 +181,9 @@ namespace NzbDrone.Core.Applications.Lidarr
{
var baseUrl = settings.BaseUrl.TrimEnd('/');
var request = new HttpRequestBuilder(baseUrl).Resource(resource)
var request = new HttpRequestBuilder(baseUrl)
.Resource(resource)
.Accept(HttpAccept.Json)
.SetHeader("X-Api-Key", settings.ApiKey)
.Build();
@ -227,9 +200,12 @@ namespace NzbDrone.Core.Applications.Lidarr
{
var response = _httpClient.Execute(request);
var results = JsonConvert.DeserializeObject<TResource>(response.Content);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
return results;
return Json.Deserialize<TResource>(response.Content);
}
}
}

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
@ -32,10 +31,10 @@ namespace NzbDrone.Core.Applications.Mylar
{
failures.AddIfNotNull(_mylarV3Proxy.TestConnection(Settings));
}
catch (WebException ex)
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Mylar"));
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Mylar. {ex.Message}"));
}
return new ValidationResult(failures);

@ -34,7 +34,7 @@ namespace NzbDrone.Core.Applications.Mylar
[FieldDefinition(1, Label = "Mylar Server", HelpText = "URL used to connect to Mylar server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8090")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Mylar in Settings/Web Interface")]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Mylar in Settings/Web Interface")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]

@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using FluentValidation.Results;
using Newtonsoft.Json;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.Applications.Mylar
{
@ -135,11 +135,11 @@ namespace NzbDrone.Core.Applications.Mylar
return new ValidationFailure("ApiKey", status.Error.Message);
}
var indexers = GetIndexers(settings);
GetIndexers(settings);
}
catch (HttpException ex)
{
_logger.Error(ex, "Unable to send test message");
_logger.Error(ex, "Unable to complete application test");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (MylarException ex)
@ -149,8 +149,8 @@ namespace NzbDrone.Core.Applications.Mylar
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
_logger.Error(ex, "Unable to complete application test");
return new ValidationFailure("", $"Unable to send test message. {ex.Message}");
}
return null;
@ -160,7 +160,9 @@ namespace NzbDrone.Core.Applications.Mylar
{
var baseUrl = settings.BaseUrl.TrimEnd('/');
var requestBuilder = new HttpRequestBuilder(baseUrl).Resource(resource)
var requestBuilder = new HttpRequestBuilder(baseUrl)
.Resource(resource)
.Accept(HttpAccept.Json)
.AddQueryParam("cmd", command)
.AddQueryParam("apikey", settings.ApiKey);
@ -187,9 +189,12 @@ namespace NzbDrone.Core.Applications.Mylar
{
var response = _httpClient.Execute(request);
var results = JsonConvert.DeserializeObject<TResource>(response.Content);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
return results;
return Json.Deserialize<TResource>(response.Content);
}
}
}

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
@ -48,9 +51,36 @@ namespace NzbDrone.Core.Applications.Radarr
{
failures.AddIfNotNull(_radarrV3Proxy.TestConnection(BuildRadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
switch (ex.Response.StatusCode)
{
case HttpStatusCode.Unauthorized:
_logger.Error(ex, "API Key is invalid");
failures.AddIfNotNull(new ValidationFailure("ApiKey", "API Key is invalid"));
break;
case HttpStatusCode.BadRequest:
_logger.Error(ex, "Prowlarr URL is invalid");
failures.AddIfNotNull(new ValidationFailure("ProwlarrUrl", "Prowlarr URL is invalid, Radarr cannot connect to Prowlarr"));
break;
case HttpStatusCode.SeeOther:
_logger.Error(ex, "Radarr returned redirect and is invalid");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Radarr URL is invalid, Prowlarr cannot connect to Radarr - are you missing a URL base?"));
break;
default:
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Radarr. {ex.Message}"));
break;
}
}
catch (JsonReaderException ex)
{
_logger.Error(ex, "Unable to parse JSON response from application");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to parse JSON response from application. {ex.Message}"));
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Radarr. {ex.Message}"));
}

@ -34,7 +34,7 @@ namespace NzbDrone.Core.Applications.Radarr
[FieldDefinition(1, Label = "Radarr Server", HelpText = "URL used to connect to Radarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:7878")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Radarr in Settings/General")]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Radarr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]

@ -92,6 +92,8 @@ namespace NzbDrone.Core.Applications.Radarr
}
catch (HttpException ex) when (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Debug("Retrying to add indexer forcefully");
request.Url = request.Url.AddQueryParam("forceSave", "true");
return ExecuteIndexerRequest(request);
@ -114,59 +116,28 @@ namespace NzbDrone.Core.Applications.Radarr
request.SetContent(indexer.ToJson());
try
{
var applicationVersion = _httpClient.Post<RadarrIndexer>(request).Headers.GetSingleValue("X-Application-Version");
var applicationVersion = _httpClient.Post(request).Headers.GetSingleValue("X-Application-Version");
if (applicationVersion == null)
{
return new ValidationFailure(string.Empty, "Failed to fetch Radarr version");
}
if (applicationVersion == null)
{
return new ValidationFailure(string.Empty, "Failed to fetch Radarr version");
}
var version = new Version(applicationVersion);
var version = new Version(applicationVersion);
if (version.Major == 3)
{
if (version < MinimumApplicationV3Version)
{
return new ValidationFailure(string.Empty, $"Radarr version should be at least {MinimumApplicationV3Version.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
}
else
if (version.Major == 3)
{
if (version < MinimumApplicationV3Version)
{
if (version < MinimumApplicationV4Version)
{
return new ValidationFailure(string.Empty, $"Radarr version should be at least {MinimumApplicationV4Version.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
return new ValidationFailure(string.Empty, $"Radarr version should be at least {MinimumApplicationV3Version.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
}
catch (HttpException ex)
else
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
if (version < MinimumApplicationV4Version)
{
_logger.Error(ex, "API Key is invalid");
return new ValidationFailure("ApiKey", "API Key is invalid");
return new ValidationFailure(string.Empty, $"Radarr version should be at least {MinimumApplicationV4Version.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Radarr cannot connect to Prowlarr");
}
if (ex.Response.StatusCode == HttpStatusCode.SeeOther)
{
_logger.Error(ex, "Radarr returned redirect and is invalid");
return new ValidationFailure("BaseUrl", "Radarr url is invalid, Prowlarr cannot connect to Radarr - are you missing a url base?");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
}
return null;
@ -223,7 +194,9 @@ namespace NzbDrone.Core.Applications.Radarr
{
var baseUrl = settings.BaseUrl.TrimEnd('/');
var request = new HttpRequestBuilder(baseUrl).Resource(resource)
var request = new HttpRequestBuilder(baseUrl)
.Resource(resource)
.Accept(HttpAccept.Json)
.SetHeader("X-Api-Key", settings.ApiKey)
.Build();
@ -240,9 +213,12 @@ namespace NzbDrone.Core.Applications.Radarr
{
var response = _httpClient.Execute(request);
var results = JsonConvert.DeserializeObject<TResource>(response.Content);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
return results;
return Json.Deserialize<TResource>(response.Content);
}
}
}

@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
@ -49,10 +51,37 @@ namespace NzbDrone.Core.Applications.Readarr
{
failures.AddIfNotNull(_readarrV1Proxy.TestConnection(BuildReadarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (WebException ex)
catch (HttpException ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Readarr"));
switch (ex.Response.StatusCode)
{
case HttpStatusCode.Unauthorized:
_logger.Error(ex, "API Key is invalid");
failures.AddIfNotNull(new ValidationFailure("ApiKey", "API Key is invalid"));
break;
case HttpStatusCode.BadRequest:
_logger.Error(ex, "Prowlarr URL is invalid");
failures.AddIfNotNull(new ValidationFailure("ProwlarrUrl", "Prowlarr URL is invalid, Readarr cannot connect to Prowlarr"));
break;
case HttpStatusCode.SeeOther:
_logger.Error(ex, "Readarr returned redirect and is invalid");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Readarr URL is invalid, Prowlarr cannot connect to Readarr - are you missing a URL base?"));
break;
default:
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Readarr. {ex.Message}"));
break;
}
}
catch (JsonReaderException ex)
{
_logger.Error(ex, "Unable to parse JSON response from application");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to parse JSON response from application. {ex.Message}"));
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Readarr. {ex.Message}"));
}
return new ValidationResult(failures);

@ -34,7 +34,7 @@ namespace NzbDrone.Core.Applications.Readarr
[FieldDefinition(1, Label = "Readarr Server", HelpText = "URL used to connect to Readarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8787")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Readarr in Settings/General")]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Readarr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]

@ -88,6 +88,8 @@ namespace NzbDrone.Core.Applications.Readarr
}
catch (HttpException ex) when (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Debug("Retrying to add indexer forcefully");
request.Url = request.Url.AddQueryParam("forceSave", "true");
return ExecuteIndexerRequest(request);
@ -110,38 +112,7 @@ namespace NzbDrone.Core.Applications.Readarr
request.SetContent(indexer.ToJson());
try
{
Execute<ReadarrIndexer>(request);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Error(ex, "API Key is invalid");
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Readarr cannot connect to Prowlarr");
}
if (ex.Response.StatusCode == HttpStatusCode.SeeOther)
{
_logger.Error(ex, "Readarr returned redirect and is invalid");
return new ValidationFailure("BaseUrl", "Readarr url is invalid, Prowlarr cannot connect to Readarr - are you missing a url base?");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
}
_httpClient.Post(request);
return null;
}
@ -197,7 +168,9 @@ namespace NzbDrone.Core.Applications.Readarr
{
var baseUrl = settings.BaseUrl.TrimEnd('/');
var request = new HttpRequestBuilder(baseUrl).Resource(resource)
var request = new HttpRequestBuilder(baseUrl)
.Resource(resource)
.Accept(HttpAccept.Json)
.SetHeader("X-Api-Key", settings.ApiKey)
.Build();
@ -214,9 +187,12 @@ namespace NzbDrone.Core.Applications.Readarr
{
var response = _httpClient.Execute(request);
var results = JsonConvert.DeserializeObject<TResource>(response.Content);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
return results;
return Json.Deserialize<TResource>(response.Content);
}
}
}

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
@ -48,9 +51,40 @@ namespace NzbDrone.Core.Applications.Sonarr
{
failures.AddIfNotNull(_sonarrV3Proxy.TestConnection(BuildSonarrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (HttpException ex)
{
switch (ex.Response.StatusCode)
{
case HttpStatusCode.Unauthorized:
_logger.Error(ex, "API Key is invalid");
failures.AddIfNotNull(new ValidationFailure("ApiKey", "API Key is invalid"));
break;
case HttpStatusCode.BadRequest:
_logger.Error(ex, "Prowlarr URL is invalid");
failures.AddIfNotNull(new ValidationFailure("ProwlarrUrl", "Prowlarr URL is invalid, Sonarr cannot connect to Prowlarr"));
break;
case HttpStatusCode.SeeOther:
_logger.Error(ex, "Sonarr returned redirect and is invalid");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Sonarr URL is invalid, Prowlarr cannot connect to Sonarr - are you missing a URL base?"));
break;
case HttpStatusCode.NotFound:
_logger.Error(ex, "Sonarr not found");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Sonarr URL is invalid, Prowlarr cannot connect to Sonarr. Is Sonarr running and accessible? Sonarr v2 is not supported."));
break;
default:
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Sonarr. {ex.Message}"));
break;
}
}
catch (JsonReaderException ex)
{
_logger.Error(ex, "Unable to parse JSON response from application");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to parse JSON response from application. {ex.Message}"));
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Sonarr. {ex.Message}"));
}

@ -34,7 +34,7 @@ namespace NzbDrone.Core.Applications.Sonarr
[FieldDefinition(1, Label = "Sonarr Server", HelpText = "URL used to connect to Sonarr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:8989")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Sonarr in Settings/General")]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Sonarr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]

@ -91,6 +91,8 @@ namespace NzbDrone.Core.Applications.Sonarr
}
catch (HttpException ex) when (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Debug("Retrying to add indexer forcefully");
request.Url = request.Url.AddQueryParam("forceSave", "true");
return ExecuteIndexerRequest(request);
@ -113,53 +115,16 @@ namespace NzbDrone.Core.Applications.Sonarr
request.SetContent(indexer.ToJson());
try
{
var applicationVersion = _httpClient.Post<SonarrIndexer>(request).Headers.GetSingleValue("X-Application-Version");
var applicationVersion = _httpClient.Post(request).Headers.GetSingleValue("X-Application-Version");
if (applicationVersion == null)
{
return new ValidationFailure(string.Empty, "Failed to fetch Sonarr version");
}
if (new Version(applicationVersion) < MinimumApplicationVersion)
{
return new ValidationFailure(string.Empty, $"Sonarr version should be at least {MinimumApplicationVersion.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
}
catch (HttpException ex)
if (applicationVersion == null)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Error(ex, "API Key is invalid");
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Sonarr cannot connect to Prowlarr");
}
if (ex.Response.StatusCode == HttpStatusCode.SeeOther)
{
_logger.Error(ex, "Sonarr returned redirect and is invalid");
return new ValidationFailure("BaseUrl", "Sonarr url is invalid, Prowlarr cannot connect to Sonarr - are you missing a url base?");
}
if (ex.Response.StatusCode == HttpStatusCode.NotFound)
{
_logger.Error(ex, "Sonarr not found");
return new ValidationFailure("BaseUrl", "Sonarr url is invalid, Prowlarr cannot connect to Sonarr. Is Sonarr running and accessible? Sonarr v2 is not supported.");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
return new ValidationFailure(string.Empty, "Failed to fetch Sonarr version");
}
catch (Exception ex)
if (new Version(applicationVersion) < MinimumApplicationVersion)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
return new ValidationFailure(string.Empty, $"Sonarr version should be at least {MinimumApplicationVersion.ToString(3)}. Version reported is {applicationVersion}", applicationVersion);
}
return null;
@ -216,7 +181,9 @@ namespace NzbDrone.Core.Applications.Sonarr
{
var baseUrl = settings.BaseUrl.TrimEnd('/');
var request = new HttpRequestBuilder(baseUrl).Resource(resource)
var request = new HttpRequestBuilder(baseUrl)
.Resource(resource)
.Accept(HttpAccept.Json)
.SetHeader("X-Api-Key", settings.ApiKey)
.Build();
@ -233,9 +200,12 @@ namespace NzbDrone.Core.Applications.Sonarr
{
var response = _httpClient.Execute(request);
var results = JsonConvert.DeserializeObject<TResource>(response.Content);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
return results;
return Json.Deserialize<TResource>(response.Content);
}
}
}

@ -3,10 +3,12 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using FluentValidation.Results;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Indexers;
@ -49,10 +51,37 @@ namespace NzbDrone.Core.Applications.Whisparr
{
failures.AddIfNotNull(_whisparrV3Proxy.TestConnection(BuildWhisparrIndexer(testIndexer, DownloadProtocol.Usenet), Settings));
}
catch (WebException ex)
catch (HttpException ex)
{
_logger.Error(ex, "Unable to send test message");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Unable to complete application test, cannot connect to Whisparr"));
switch (ex.Response.StatusCode)
{
case HttpStatusCode.Unauthorized:
_logger.Error(ex, "API Key is invalid");
failures.AddIfNotNull(new ValidationFailure("ApiKey", "API Key is invalid"));
break;
case HttpStatusCode.BadRequest:
_logger.Error(ex, "Prowlarr URL is invalid");
failures.AddIfNotNull(new ValidationFailure("ProwlarrUrl", "Prowlarr URL is invalid, Whisparr cannot connect to Prowlarr"));
break;
case HttpStatusCode.SeeOther:
_logger.Error(ex, "Whisparr returned redirect and is invalid");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", "Whisparr URL is invalid, Prowlarr cannot connect to Whisparr - are you missing a URL base?"));
break;
default:
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Whisparr. {ex.Message}"));
break;
}
}
catch (JsonReaderException ex)
{
_logger.Error(ex, "Unable to parse JSON response from application");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to parse JSON response from application. {ex.Message}"));
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to complete application test");
failures.AddIfNotNull(new ValidationFailure("BaseUrl", $"Unable to complete application test, cannot connect to Whisparr. {ex.Message}"));
}
return new ValidationResult(failures);

@ -34,7 +34,7 @@ namespace NzbDrone.Core.Applications.Whisparr
[FieldDefinition(1, Label = "Whisparr Server", HelpText = "URL used to connect to Whisparr server, including http(s)://, port, and urlbase if required", Placeholder = "http://localhost:6969")]
public string BaseUrl { get; set; }
[FieldDefinition(2, Label = "ApiKey", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Whisparr in Settings/General")]
[FieldDefinition(2, Label = "API Key", Privacy = PrivacyLevel.ApiKey, HelpText = "The ApiKey generated by Whisparr in Settings/General")]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Sync Categories", Type = FieldType.Select, SelectOptions = typeof(NewznabCategoryFieldConverter), Advanced = true, HelpText = "Only Indexers that support these categories will be synced")]

@ -110,38 +110,7 @@ namespace NzbDrone.Core.Applications.Whisparr
request.SetContent(indexer.ToJson());
try
{
Execute<WhisparrIndexer>(request);
}
catch (HttpException ex)
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
_logger.Error(ex, "API Key is invalid");
return new ValidationFailure("ApiKey", "API Key is invalid");
}
if (ex.Response.StatusCode == HttpStatusCode.BadRequest)
{
_logger.Error(ex, "Prowlarr URL is invalid");
return new ValidationFailure("ProwlarrUrl", "Prowlarr url is invalid, Whisparr cannot connect to Prowlarr");
}
if (ex.Response.StatusCode == HttpStatusCode.SeeOther)
{
_logger.Error(ex, "Whisparr returned redirect and is invalid");
return new ValidationFailure("BaseUrl", "Whisparr url is invalid, Prowlarr cannot connect to Whisparr - are you missing a url base?");
}
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("BaseUrl", "Unable to complete application test");
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send test message");
return new ValidationFailure("", "Unable to send test message");
}
_httpClient.Post(request);
return null;
}
@ -197,7 +166,9 @@ namespace NzbDrone.Core.Applications.Whisparr
{
var baseUrl = settings.BaseUrl.TrimEnd('/');
var request = new HttpRequestBuilder(baseUrl).Resource(resource)
var request = new HttpRequestBuilder(baseUrl)
.Resource(resource)
.Accept(HttpAccept.Json)
.SetHeader("X-Api-Key", settings.ApiKey)
.Build();
@ -214,9 +185,12 @@ namespace NzbDrone.Core.Applications.Whisparr
{
var response = _httpClient.Execute(request);
var results = JsonConvert.DeserializeObject<TResource>(response.Content);
if ((int)response.StatusCode >= 300)
{
throw new HttpException(response);
}
return results;
return Json.Deserialize<TResource>(response.Content);
}
}
}

Loading…
Cancel
Save