mirror of
https://github.com/Radarr/Radarr
synced 2025-01-31 11:53:06 +00:00
Validate newznab indexers when adding
This commit is contained in:
parent
34b5a833f5
commit
f0e721ee80
8 changed files with 87 additions and 6 deletions
|
@ -4,11 +4,11 @@ namespace NzbDrone.Core.Exceptions
|
||||||
{
|
{
|
||||||
public class BadRequestException : DownstreamException
|
public class BadRequestException : DownstreamException
|
||||||
{
|
{
|
||||||
public BadRequestException(HttpStatusCode statusCode, string message) : base(statusCode, message)
|
public BadRequestException(string message) : base(HttpStatusCode.BadRequest, message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public BadRequestException(HttpStatusCode statusCode, string message, params object[] args) : base(statusCode, message, args)
|
public BadRequestException(string message, params object[] args) : base(HttpStatusCode.BadRequest, message, args)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ public static void VerifyStatusCode(this HttpStatusCode statusCode, string messa
|
||||||
switch (statusCode)
|
switch (statusCode)
|
||||||
{
|
{
|
||||||
case HttpStatusCode.BadRequest:
|
case HttpStatusCode.BadRequest:
|
||||||
throw new BadRequestException(statusCode, message);
|
throw new BadRequestException(message);
|
||||||
|
|
||||||
case HttpStatusCode.Unauthorized:
|
case HttpStatusCode.Unauthorized:
|
||||||
throw new UnauthorizedAccessException(message);
|
throw new UnauthorizedAccessException(message);
|
||||||
|
|
|
@ -37,14 +37,20 @@ public class IndexerService : IIndexerService, IHandle<ApplicationStartedEvent>
|
||||||
{
|
{
|
||||||
private readonly IIndexerRepository _indexerRepository;
|
private readonly IIndexerRepository _indexerRepository;
|
||||||
private readonly IConfigFileProvider _configFileProvider;
|
private readonly IConfigFileProvider _configFileProvider;
|
||||||
|
private readonly INewznabTestService _newznabTestService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
private readonly List<IIndexer> _indexers;
|
private readonly List<IIndexer> _indexers;
|
||||||
|
|
||||||
public IndexerService(IIndexerRepository indexerRepository, IEnumerable<IIndexer> indexers, IConfigFileProvider configFileProvider, Logger logger)
|
public IndexerService(IIndexerRepository indexerRepository,
|
||||||
|
IEnumerable<IIndexer> indexers,
|
||||||
|
IConfigFileProvider configFileProvider,
|
||||||
|
INewznabTestService newznabTestService,
|
||||||
|
Logger logger)
|
||||||
{
|
{
|
||||||
_indexerRepository = indexerRepository;
|
_indexerRepository = indexerRepository;
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
|
_newznabTestService = newznabTestService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,6 +110,9 @@ public Indexer Create(Indexer indexer)
|
||||||
Settings = indexer.Settings.ToJson()
|
Settings = indexer.Settings.ToJson()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var instance = ToIndexer(definition).Instance;
|
||||||
|
_newznabTestService.Test(instance);
|
||||||
|
|
||||||
definition = _indexerRepository.Insert(definition);
|
definition = _indexerRepository.Insert(definition);
|
||||||
indexer.Id = definition.Id;
|
indexer.Id = definition.Id;
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,6 @@ public override IEnumerable<string> GetSeasonSearchUrls(string seriesTitle, int
|
||||||
return RecentFeed.Select(url => String.Format("{0}&limit=100&q={1}&season={2}&offset={3}", url, NewsnabifyTitle(seriesTitle), seasonNumber, offset));
|
return RecentFeed.Select(url => String.Format("{0}&limit=100&q={1}&season={2}&offset={3}", url, NewsnabifyTitle(seriesTitle), seasonNumber, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override string Name
|
public override string Name
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -131,7 +130,6 @@ public override IndexerKind Kind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static string NewsnabifyTitle(string title)
|
private static string NewsnabifyTitle(string title)
|
||||||
{
|
{
|
||||||
return title.Replace("+", "%20");
|
return title.Replace("+", "%20");
|
||||||
|
|
54
NzbDrone.Core/Indexers/NewznabTestService.cs
Normal file
54
NzbDrone.Core/Indexers/NewznabTestService.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Indexers
|
||||||
|
{
|
||||||
|
public interface INewznabTestService
|
||||||
|
{
|
||||||
|
void Test(IIndexer indexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NewznabTestService : INewznabTestService
|
||||||
|
{
|
||||||
|
private readonly IFetchFeedFromIndexers _feedFetcher;
|
||||||
|
private readonly IHttpProvider _httpProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public NewznabTestService(IFetchFeedFromIndexers feedFetcher, IHttpProvider httpProvider, Logger logger)
|
||||||
|
{
|
||||||
|
_feedFetcher = feedFetcher;
|
||||||
|
_httpProvider = httpProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Test(IIndexer indexer)
|
||||||
|
{
|
||||||
|
var releases = _feedFetcher.FetchRss(indexer);
|
||||||
|
|
||||||
|
if (releases.Any()) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_httpProvider.DownloadString(indexer.RecentFeed.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_logger.Warn("No result returned from RSS Feed, please confirm you're using a newznab indexer");
|
||||||
|
|
||||||
|
var failure = new ValidationFailure("Url", "Invalid Newznab URL entered");
|
||||||
|
throw new ValidationException(new List<ValidationFailure> { failure }.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Warn("Indexer returned result for Newznab RSS URL, API Key appears to be invalid");
|
||||||
|
|
||||||
|
var apiKeyFailure = new ValidationFailure("ApiKey", "Invalid API Key");
|
||||||
|
throw new ValidationException(new List<ValidationFailure> { apiKeyFailure }.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -238,6 +238,7 @@
|
||||||
<Compile Include="Indexers\FetchAndParseRssService.cs" />
|
<Compile Include="Indexers\FetchAndParseRssService.cs" />
|
||||||
<Compile Include="Indexers\IIndexer.cs" />
|
<Compile Include="Indexers\IIndexer.cs" />
|
||||||
<Compile Include="Indexers\IndexerSettingUpdatedEvent.cs" />
|
<Compile Include="Indexers\IndexerSettingUpdatedEvent.cs" />
|
||||||
|
<Compile Include="Indexers\NewznabTestService.cs" />
|
||||||
<Compile Include="Indexers\IndexerWithSetting.cs" />
|
<Compile Include="Indexers\IndexerWithSetting.cs" />
|
||||||
<Compile Include="Indexers\IParseFeed.cs" />
|
<Compile Include="Indexers\IParseFeed.cs" />
|
||||||
<Compile Include="Indexers\Newznab\SizeParsingException.cs" />
|
<Compile Include="Indexers\Newznab\SizeParsingException.cs" />
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
{{#if id}}
|
{{#if id}}
|
||||||
<button class="btn btn-danger pull-left x-remove">delete</button>
|
<button class="btn btn-danger pull-left x-remove">delete</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
<span class="x-activity"></span>
|
||||||
|
|
||||||
<button class="btn" data-dismiss="modal">cancel</button>
|
<button class="btn" data-dismiss="modal">cancel</button>
|
||||||
|
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
|
|
|
@ -11,6 +11,10 @@ define(
|
||||||
var view = Marionette.ItemView.extend({
|
var view = Marionette.ItemView.extend({
|
||||||
template: 'Settings/Indexers/EditTemplate',
|
template: 'Settings/Indexers/EditTemplate',
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
activity: '.x-activity'
|
||||||
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
'click .x-save' : '_save',
|
'click .x-save' : '_save',
|
||||||
'click .x-save-and-add': '_saveAndAdd'
|
'click .x-save-and-add': '_saveAndAdd'
|
||||||
|
@ -21,6 +25,8 @@ define(
|
||||||
},
|
},
|
||||||
|
|
||||||
_save: function () {
|
_save: function () {
|
||||||
|
this.ui.activity.html('<i class="icon-nd-spinner"></i>');
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var promise = this.model.saveSettings();
|
var promise = this.model.saveSettings();
|
||||||
|
|
||||||
|
@ -29,10 +35,16 @@ define(
|
||||||
self.indexerCollection.add(self.model, { merge: true });
|
self.indexerCollection.add(self.model, { merge: true });
|
||||||
App.vent.trigger(App.Commands.CloseModalCommand);
|
App.vent.trigger(App.Commands.CloseModalCommand);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
promise.always(function () {
|
||||||
|
self.ui.activity.empty();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_saveAndAdd: function () {
|
_saveAndAdd: function () {
|
||||||
|
this.ui.activity.html('<i class="icon-nd-spinner"></i>');
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var promise = this.model.saveSettings();
|
var promise = this.model.saveSettings();
|
||||||
|
|
||||||
|
@ -50,6 +62,10 @@ define(
|
||||||
self.model.set('fields.' + key + '.value', '');
|
self.model.set('fields.' + key + '.value', '');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
promise.always(function () {
|
||||||
|
self.ui.activity.empty();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue