New: Added Presets to Indexers to add indexers with default properties. In an older version of NzbDrone these default indexers were added automatically and could not be removed.

pull/4/head
Taloth Saldono 10 years ago
parent 6184105d3c
commit 9633afc612

@ -5,6 +5,7 @@ using NzbDrone.Common;
using NzbDrone.Common.EnsureThat;
using NzbDrone.Common.Reflection;
using NzbDrone.Core.Annotations;
using Omu.ValueInjecter;
namespace NzbDrone.Api.ClientSchema
{
@ -55,7 +56,7 @@ namespace NzbDrone.Api.ClientSchema
}
public static object ReadFormSchema(List<Field> fields, Type targetType)
public static object ReadFormSchema(List<Field> fields, Type targetType, object defaults = null)
{
Ensure.That(targetType, () => targetType).IsNotNull();
@ -63,6 +64,11 @@ namespace NzbDrone.Api.ClientSchema
var target = Activator.CreateInstance(targetType);
if (defaults != null)
{
target.InjectFrom(defaults);
}
foreach (var propertyInfo in properties)
{
var fieldAttribute = propertyInfo.GetAttribute<FieldDefinitionAttribute>(false);

@ -1,37 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Core.Download;
using Omu.ValueInjecter;
namespace NzbDrone.Api.DownloadClient
{
public class DownloadClientSchemaModule : NzbDroneRestModule<DownloadClientResource>
{
private readonly IDownloadClientFactory _downloadClientFactory;
public DownloadClientSchemaModule(IDownloadClientFactory downloadClientFactory)
: base("downloadclient/schema")
{
_downloadClientFactory = downloadClientFactory;
GetResourceAll = GetSchema;
}
private List<DownloadClientResource> GetSchema()
{
var downloadClients = _downloadClientFactory.Templates();
var result = new List<DownloadClientResource>(downloadClients.Count);
foreach (var downloadClient in downloadClients)
{
var downloadClientResource = new DownloadClientResource();
downloadClientResource.InjectFrom(downloadClient);
downloadClientResource.Fields = SchemaBuilder.ToSchema(downloadClient.Settings);
result.Add(downloadClientResource);
}
return result;
}
}
}

@ -1,38 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Core.Indexers;
using Omu.ValueInjecter;
namespace NzbDrone.Api.Indexers
{
public class IndexerSchemaModule : NzbDroneRestModule<IndexerResource>
{
private readonly IIndexerFactory _indexerFactory;
public IndexerSchemaModule(IIndexerFactory indexerFactory)
: base("indexer/schema")
{
_indexerFactory = indexerFactory;
GetResourceAll = GetSchema;
}
private List<IndexerResource> GetSchema()
{
var indexers = _indexerFactory.Templates();
var result = new List<IndexerResource>(indexers.Count());
foreach (var indexer in indexers)
{
var indexerResource = new IndexerResource();
indexerResource.InjectFrom(indexer);
indexerResource.Fields = SchemaBuilder.ToSchema(indexer.Settings);
result.Add(indexerResource);
}
return result;
}
}
}

@ -1,37 +0,0 @@
using System.Collections.Generic;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Core.Notifications;
using Omu.ValueInjecter;
namespace NzbDrone.Api.Notifications
{
public class NotificationSchemaModule : NzbDroneRestModule<NotificationResource>
{
private readonly INotificationFactory _notificationFactory;
public NotificationSchemaModule(INotificationFactory notificationFactory)
: base("notification/schema")
{
_notificationFactory = notificationFactory;
GetResourceAll = GetSchema;
}
private List<NotificationResource> GetSchema()
{
var notifications = _notificationFactory.Templates();
var result = new List<NotificationResource>(notifications.Count);
foreach (var notification in notifications)
{
var notificationResource = new NotificationResource();
notificationResource.InjectFrom(notification);
notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings);
result.Add(notificationResource);
}
return result;
}
}
}

@ -144,11 +144,9 @@
<Compile Include="MediaCovers\MediaCoverModule.cs" />
<Compile Include="Metadata\MetadataResource.cs" />
<Compile Include="Metadata\MetadataModule.cs" />
<Compile Include="Notifications\NotificationSchemaModule.cs" />
<Compile Include="NzbDroneFeedModule.cs" />
<Compile Include="ProviderResource.cs" />
<Compile Include="ProviderModuleBase.cs" />
<Compile Include="Indexers\IndexerSchemaModule.cs" />
<Compile Include="Indexers\IndexerModule.cs" />
<Compile Include="Indexers\IndexerResource.cs" />
<Compile Include="Indexers\ReleaseModule.cs" />
@ -172,7 +170,6 @@
<Compile Include="Queue\QueueModule.cs" />
<Compile Include="Queue\QueueResource.cs" />
<Compile Include="ResourceChangeMessage.cs" />
<Compile Include="DownloadClient\DownloadClientSchemaModule.cs" />
<Compile Include="Notifications\NotificationModule.cs" />
<Compile Include="Notifications\NotificationResource.cs" />
<Compile Include="NzbDroneRestModule.cs" />

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using Nancy;
@ -22,7 +23,7 @@ namespace NzbDrone.Api
: base(resource)
{
_providerFactory = providerFactory;
Get["templates"] = x => GetTemplates();
Get["schema"] = x => GetTemplates();
GetResourceAll = GetAll;
GetResourceById = GetProviderById;
CreateResource = CreateProvider;
@ -82,8 +83,13 @@ namespace NzbDrone.Api
definition.InjectFrom(providerResource);
var preset = _providerFactory.GetPresetDefinitions(definition)
.Where(v => v.Name == definition.Name)
.Select(v => v.Settings)
.FirstOrDefault();
var configContract = ReflectionExtensions.CoreAssembly.FindTypeByName(definition.ConfigContract);
definition.Settings = (IProviderConfig)SchemaBuilder.ReadFormSchema(providerResource.Fields, configContract);
definition.Settings = (IProviderConfig)SchemaBuilder.ReadFormSchema(providerResource.Fields, configContract, preset);
Validate(definition);
@ -97,15 +103,29 @@ namespace NzbDrone.Api
private Response GetTemplates()
{
var templates = _providerFactory.Templates();
var defaultDefinitions = _providerFactory.GetDefaultDefinitions();
var result = new List<TProviderResource>(templates.Count());
var result = new List<TProviderResource>(defaultDefinitions.Count());
foreach (var providerDefinition in templates)
foreach (var providerDefinition in defaultDefinitions)
{
var providerResource = new TProviderResource();
providerResource.InjectFrom(providerDefinition);
providerResource.Fields = SchemaBuilder.ToSchema(providerDefinition.Settings);
providerResource.InfoLink = String.Format("https://github.com/NzbDrone/NzbDrone/wiki/Supported-{0}#{1}",
typeof(TProviderResource).Name.Replace("Resource", "s"),
providerDefinition.Implementation.ToLower());
var presetDefinitions = _providerFactory.GetPresetDefinitions(providerDefinition);
providerResource.Presets = presetDefinitions.Select(v =>
{
var presetResource = new TProviderResource();
presetResource.InjectFrom(v);
presetResource.Fields = SchemaBuilder.ToSchema(v.Settings);
return presetResource as ProviderResource;
}).ToList();
result.Add(providerResource);
}

@ -11,5 +11,8 @@ namespace NzbDrone.Api
public List<Field> Fields { get; set; }
public String Implementation { get; set; }
public String ConfigContract { get; set; }
public String InfoLink { get; set; }
public List<ProviderResource> Presets { get; set; }
}
}

@ -27,9 +27,9 @@ namespace NzbDrone.Core.Download
return base.Active().Where(c => c.Enable).ToList();
}
protected override DownloadClientDefinition GetTemplate(IDownloadClient provider)
protected override DownloadClientDefinition GetProviderCharacteristics(IDownloadClient provider, DownloadClientDefinition definition)
{
var definition = base.GetTemplate(provider);
definition = base.GetProviderCharacteristics(provider, definition);
definition.Protocol = provider.Protocol;

@ -50,9 +50,9 @@ namespace NzbDrone.Core.Indexers
return base.Create(definition);
}
protected override IndexerDefinition GetTemplate(IIndexer provider)
protected override IndexerDefinition GetProviderCharacteristics(IIndexer provider, IndexerDefinition definition)
{
var definition = base.GetTemplate(provider);
definition = base.GetProviderCharacteristics(provider, definition);
definition.Protocol = provider.Protocol;

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace NzbDrone.Core.ThingiProvider
{
@ -12,6 +13,7 @@ namespace NzbDrone.Core.ThingiProvider
TProviderDefinition Create(TProviderDefinition indexer);
void Update(TProviderDefinition indexer);
void Delete(int id);
List<TProviderDefinition> Templates();
IEnumerable<TProviderDefinition> GetDefaultDefinitions();
IEnumerable<TProviderDefinition> GetPresetDefinitions(TProviderDefinition providerDefinition);
}
}

@ -38,9 +38,41 @@ namespace NzbDrone.Core.ThingiProvider
return _providerRepository.All().ToList();
}
public List<TProviderDefinition> Templates()
public IEnumerable<TProviderDefinition> GetDefaultDefinitions()
{
return _providers.Select(GetTemplate).ToList();
foreach (var provider in _providers)
{
var definition = provider.DefaultDefinitions
.OfType<TProviderDefinition>()
.FirstOrDefault(v => v.Name == null || v.Name == provider.GetType().Name);
if (definition == null)
{
definition = new TProviderDefinition()
{
Name = string.Empty,
ConfigContract = provider.ConfigContract.Name,
Implementation = provider.GetType().Name,
Settings = (IProviderConfig)Activator.CreateInstance(provider.ConfigContract)
};
}
definition = GetProviderCharacteristics(provider, definition);
yield return definition;
}
}
public IEnumerable<TProviderDefinition> GetPresetDefinitions(TProviderDefinition providerDefinition)
{
var provider = _providers.First(v => v.GetType().Name == providerDefinition.Implementation);
var definitions = provider.DefaultDefinitions
.OfType<TProviderDefinition>()
.Where(v => v.Name != null && v.Name != provider.GetType().Name)
.ToList();
return definitions;
}
public List<TProvider> GetAvailableProviders()
@ -82,18 +114,6 @@ namespace NzbDrone.Core.ThingiProvider
return _providers.Select(c => c.GetType()).SingleOrDefault(c => c.Name.Equals(definition.Implementation, StringComparison.InvariantCultureIgnoreCase));
}
protected virtual TProviderDefinition GetTemplate(TProvider provider)
{
var definition = new TProviderDefinition()
{
ConfigContract = provider.ConfigContract.Name,
Implementation = provider.GetType().Name,
Settings = (IProviderConfig)Activator.CreateInstance(provider.ConfigContract)
};
return definition;
}
public void Handle(ApplicationStartedEvent message)
{
_logger.Debug("Initializing Providers. Count {0}", _providers.Count);
@ -112,6 +132,11 @@ namespace NzbDrone.Core.ThingiProvider
return All().Where(c => c.Settings.Validate().IsValid).ToList();
}
protected virtual TProviderDefinition GetProviderCharacteristics(TProvider provider, TProviderDefinition definition)
{
return definition;
}
private void RemoveMissingImplementations()
{
var storedProvider = _providerRepository.All();

@ -1,32 +1,51 @@
'use strict';
define([
'underscore',
'jquery',
'AppLayout',
'marionette',
'Settings/DownloadClient/Edit/DownloadClientEditView'
], function ($, AppLayout, Marionette, EditView) {
], function (_, $, AppLayout, Marionette, EditView) {
return Marionette.ItemView.extend({
template: 'Settings/DownloadClient/Add/DownloadClientAddItemViewTemplate',
tagName : 'li',
template : 'Settings/DownloadClient/Add/DownloadClientAddItemViewTemplate',
tagName : 'li',
className : 'add-thingy-item',
events: {
'click': '_add'
'click .x-preset': '_addPreset',
'click' : '_add'
},
initialize: function (options) {
this.targetCollection = options.targetCollection;
},
_addPreset: function (e) {
var presetName = $(e.target).closest('.x-preset').attr('data-id');
var presetData = _.where(this.model.get('presets'), {name: presetName})[0];
this.model.set(presetData);
this.model.set({
id : undefined,
enable : true
});
var editView = new EditView({ model: this.model, targetCollection: this.targetCollection });
AppLayout.modalRegion.show(editView);
},
_add: function (e) {
if (this.$(e.target).hasClass('icon-info-sign')) {
if ($(e.target).closest('.btn,.btn-group').length !== 0) {
return;
}
this.model.set({
id : undefined,
name : this.model.get('implementation'),
enable : true
});

@ -1,6 +1,27 @@
<div class="add-thingy">
{{implementation}}
{{#if link}}
<a href="{{link}}"><i class="icon-info-sign"/></a>
{{/if}}
<div>
{{implementation}}
</div>
<div class="pull-right">
{{#if_gt presets.length compare=0}}
<div class="btn-group">
<button class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
Presets
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{{#each presets}}
<li class="x-preset" data-id="{{name}}">
<a>{{name}}</a>
</li>
{{/each}}
</ul>
</div>
{{/if_gt}}
{{#if infoLink}}
<a class="btn btn-xs btn-default x-info" href="{{infoLink}}">
<i class="icon-info-sign"/>
</a>
{{/if}}
</div>
</div>

@ -27,7 +27,7 @@
}
.add-download-client {
li {
li.add-thingy-item {
width: 33%;
}
}

@ -1,32 +1,51 @@
'use strict';
define([
'underscore',
'jquery',
'AppLayout',
'marionette',
'Settings/Indexers/Edit/IndexerEditView'
], function ($, AppLayout, Marionette, EditView) {
], function (_, $, AppLayout, Marionette, EditView) {
return Marionette.ItemView.extend({
template: 'Settings/Indexers/Add/IndexerAddItemViewTemplate',
tagName : 'li',
template : 'Settings/Indexers/Add/IndexerAddItemViewTemplate',
tagName : 'li',
className : 'add-thingy-item',
events: {
'click': '_add'
'click .x-preset': '_addPreset',
'click' : '_add'
},
initialize: function (options) {
this.targetCollection = options.targetCollection;
},
_addPreset: function (e) {
var presetName = $(e.target).closest('.x-preset').attr('data-id');
var presetData = _.where(this.model.get('presets'), {name: presetName})[0];
this.model.set(presetData);
this.model.set({
id : undefined,
enable : true
});
var editView = new EditView({ model: this.model, targetCollection: this.targetCollection });
AppLayout.modalRegion.show(editView);
},
_add: function (e) {
if (this.$(e.target).hasClass('icon-info-sign')) {
if ($(e.target).closest('.btn,.btn-group').length !== 0) {
return;
}
this.model.set({
id : undefined,
name : undefined,
enable : true
});

@ -1,6 +1,27 @@
<div class="add-thingy">
{{implementation}}
{{#if link}}
<a href="{{link}}"><i class="icon-info-sign"/></a>
{{/if}}
<div>
{{implementation}}
</div>
<div class="pull-right">
{{#if_gt presets.length compare=0}}
<div class="btn-group">
<button class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
Presets
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{{#each presets}}
<li class="x-preset" data-id="{{name}}">
<a>{{name}}</a>
</li>
{{/each}}
</ul>
</div>
{{/if_gt}}
{{#if infoLink}}
<a class="btn btn-xs btn-default x-info" href="{{infoLink}}">
<i class="icon-info-sign"/>
</a>
{{/if}}
</div>
</div>

@ -27,7 +27,7 @@
}
.add-indexer {
li {
li.add-thingy-item {
width: 33%;
}
}

@ -1,32 +1,53 @@
'use strict';
define([
'underscore',
'jquery',
'AppLayout',
'marionette',
'Settings/Notifications/Edit/NotificationEditView'
], function ($, AppLayout, Marionette, EditView) {
], function (_, $, AppLayout, Marionette, EditView) {
return Marionette.ItemView.extend({
template: 'Settings/Notifications/Add/NotificationAddItemViewTemplate',
tagName : 'li',
template : 'Settings/Notifications/Add/NotificationAddItemViewTemplate',
tagName : 'li',
className : 'add-thingy-item',
events: {
'click': '_add'
'click .x-preset': '_addPreset',
'click' : '_add'
},
initialize: function (options) {
this.targetCollection = options.targetCollection;
},
_addPreset: function (e) {
var presetName = $(e.target).closest('.x-preset').attr('data-id');
var presetData = _.where(this.model.get('presets'), {name: presetName})[0];
this.model.set(presetData);
this.model.set({
id : undefined,
onGrab : true,
onDownload : true,
onUpgrade : true
});
var editView = new EditView({ model: this.model, targetCollection: this.targetCollection });
AppLayout.modalRegion.show(editView);
},
_add: function (e) {
if (this.$(e.target).hasClass('icon-info-sign')) {
if ($(e.target).closest('.btn,.btn-group').length !== 0) {
return;
}
this.model.set({
id : undefined,
name : this.model.get('implementation'),
onGrab : true,
onDownload : true,
onUpgrade : true

@ -1,6 +1,27 @@
<div class="add-thingy">
{{implementation}}
{{#if link}}
<a href="{{link}}"><i class="icon-info-sign"/></a>
{{/if}}
<div>
{{implementation}}
</div>
<div class="pull-right">
{{#if_gt presets.length compare=0}}
<div class="btn-group">
<button class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
Presets
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{{#each presets}}
<li class="x-preset" data-id="{{name}}">
<a>{{name}}</a>
</li>
{{/each}}
</ul>
</div>
{{/if_gt}}
{{#if infoLink}}
<a class="btn btn-xs btn-default x-info" href="{{infoLink}}">
<i class="icon-info-sign"/>
</a>
{{/if}}
</div>
</div>

@ -25,7 +25,7 @@
}
.add-notifications {
li {
li.add-thingy-item {
width: 40%;
}
}

@ -7,19 +7,7 @@
font-size: 24px;
font-weight: lighter;
text-align: center;
a {
font-size: 16px;
color: #595959;
i {
.clickable;
}
}
a:hover {
text-decoration: none;
}
height: 85px;
}
.add-thingies {
@ -30,12 +18,12 @@
text-transform: capitalize;
}
.items {
ul.items {
list-style-type: none;
margin: 0px;
padding: 0px;
li {
li.add-thingy-item {
display: inline-block;
vertical-align: top;
}

Loading…
Cancel
Save