diff --git a/src/NzbDrone.Api/Config/NetImportConfigModule.cs b/src/NzbDrone.Api/Config/NetImportConfigModule.cs new file mode 100644 index 000000000..3cd194116 --- /dev/null +++ b/src/NzbDrone.Api/Config/NetImportConfigModule.cs @@ -0,0 +1,20 @@ +using FluentValidation; +using NzbDrone.Api.Validation; +using NzbDrone.Core.Configuration; + +namespace NzbDrone.Api.Config +{ + public class NetImportConfigModule : NzbDroneConfigModule + { + + public NetImportConfigModule(IConfigService configService) + : base(configService) + { + } + + protected override NetImportConfigResource ToResource(IConfigService model) + { + return NetImportConfigResourceMapper.ToResource(model); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Api/Config/NetImportConfigResource.cs b/src/NzbDrone.Api/Config/NetImportConfigResource.cs new file mode 100644 index 000000000..7b32aefe3 --- /dev/null +++ b/src/NzbDrone.Api/Config/NetImportConfigResource.cs @@ -0,0 +1,19 @@ +using NzbDrone.Api.REST; +using NzbDrone.Core.Configuration; + +namespace NzbDrone.Api.Config +{ + public class NetImportConfigResource : RestResource + { + } + + public static class NetImportConfigResourceMapper + { + public static NetImportConfigResource ToResource(IConfigService model) + { + return new NetImportConfigResource + { + }; + } + } +} diff --git a/src/NzbDrone.Api/NetImport/NetImportModule.cs b/src/NzbDrone.Api/NetImport/NetImportModule.cs index b128b061d..6130191d7 100644 --- a/src/NzbDrone.Api/NetImport/NetImportModule.cs +++ b/src/NzbDrone.Api/NetImport/NetImportModule.cs @@ -5,7 +5,7 @@ namespace NzbDrone.Api.NetImport public class NetImportModule : ProviderModuleBase { public NetImportModule(NetImportFactory indexerFactory) - : base(indexerFactory, "indexer") + : base(indexerFactory, "netimport") { } diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index 6a61d84fc..47a433a54 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -109,6 +109,8 @@ + + @@ -121,6 +123,8 @@ + + diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index a2607ca25..c8dd24853 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -125,6 +125,7 @@ + diff --git a/src/UI/Settings/NetImport/Add/IndexerAddCollectionView.js b/src/UI/Settings/NetImport/Add/IndexerAddCollectionView.js new file mode 100644 index 000000000..5a4102cf2 --- /dev/null +++ b/src/UI/Settings/NetImport/Add/IndexerAddCollectionView.js @@ -0,0 +1,9 @@ +var ThingyAddCollectionView = require('../../ThingyAddCollectionView'); +var ThingyHeaderGroupView = require('../../ThingyHeaderGroupView'); +var AddItemView = require('./IndexerAddItemView'); + +module.exports = ThingyAddCollectionView.extend({ + itemView : ThingyHeaderGroupView.extend({ itemView : AddItemView }), + itemViewContainer : '.add-indexer .items', + template : 'Settings/Indexers/Add/IndexerAddCollectionViewTemplate' +}); \ No newline at end of file diff --git a/src/UI/Settings/NetImport/Add/IndexerAddCollectionViewTemplate.hbs b/src/UI/Settings/NetImport/Add/IndexerAddCollectionViewTemplate.hbs new file mode 100644 index 000000000..3d581b5e4 --- /dev/null +++ b/src/UI/Settings/NetImport/Add/IndexerAddCollectionViewTemplate.hbs @@ -0,0 +1,18 @@ + diff --git a/src/UI/Settings/NetImport/Add/IndexerAddItemView.js b/src/UI/Settings/NetImport/Add/IndexerAddItemView.js new file mode 100644 index 000000000..3a8b0493a --- /dev/null +++ b/src/UI/Settings/NetImport/Add/IndexerAddItemView.js @@ -0,0 +1,52 @@ +var _ = require('underscore'); +var $ = require('jquery'); +var AppLayout = require('../../../AppLayout'); +var Marionette = require('marionette'); +var EditView = require('../Edit/IndexerEditView'); + +module.exports = Marionette.ItemView.extend({ + template : 'Settings/Indexers/Add/IndexerAddItemViewTemplate', + tagName : 'li', + className : 'add-thingy-item', + + events : { + '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._openEdit(); + }, + + _add : function(e) { + if ($(e.target).closest('.btn,.btn-group').length !== 0 && $(e.target).closest('.x-custom').length === 0) { + return; + } + + this._openEdit(); + }, + + _openEdit : function() { + this.model.set({ + id : undefined, + enableRss : this.model.get('supportsRss'), + enableSearch : this.model.get('supportsSearch') + }); + + var editView = new EditView({ + model : this.model, + targetCollection : this.targetCollection + }); + + AppLayout.modalRegion.show(editView); + } +}); \ No newline at end of file diff --git a/src/UI/Settings/NetImport/Add/IndexerAddItemViewTemplate.hbs b/src/UI/Settings/NetImport/Add/IndexerAddItemViewTemplate.hbs new file mode 100644 index 000000000..40bcb4391 --- /dev/null +++ b/src/UI/Settings/NetImport/Add/IndexerAddItemViewTemplate.hbs @@ -0,0 +1,30 @@ +
+
+ {{implementationName}} +
+
+ {{#if_gt presets.length compare=0}} + +
+ + +
+ {{/if_gt}} + {{#if infoLink}} + + + + {{/if}} +
+
\ No newline at end of file diff --git a/src/UI/Settings/NetImport/Add/IndexerSchemaModal.js b/src/UI/Settings/NetImport/Add/IndexerSchemaModal.js new file mode 100644 index 000000000..52b430e89 --- /dev/null +++ b/src/UI/Settings/NetImport/Add/IndexerSchemaModal.js @@ -0,0 +1,39 @@ +var _ = require('underscore'); +var AppLayout = require('../../../AppLayout'); +var Backbone = require('backbone'); +var SchemaCollection = require('../IndexerCollection'); +var AddCollectionView = require('./IndexerAddCollectionView'); + +module.exports = { + open : function(collection) { + var schemaCollection = new SchemaCollection(); + var originalUrl = schemaCollection.url; + schemaCollection.url = schemaCollection.url + '/schema'; + schemaCollection.fetch(); + schemaCollection.url = originalUrl; + + var groupedSchemaCollection = new Backbone.Collection(); + + schemaCollection.on('sync', function() { + + var groups = schemaCollection.groupBy(function(model, iterator) { + return model.get('protocol'); + }); + var modelCollection = _.map(groups, function(values, key, list) { + return { + "header" : key, + collection : values + }; + }); + + groupedSchemaCollection.reset(modelCollection); + }); + + var view = new AddCollectionView({ + collection : groupedSchemaCollection, + targetCollection : collection + }); + + AppLayout.modalRegion.show(view); + } +}; \ No newline at end of file diff --git a/src/UI/Settings/NetImport/Delete/IndexerDeleteView.js b/src/UI/Settings/NetImport/Delete/IndexerDeleteView.js new file mode 100644 index 000000000..58e7e3eb5 --- /dev/null +++ b/src/UI/Settings/NetImport/Delete/IndexerDeleteView.js @@ -0,0 +1,19 @@ +var vent = require('vent'); +var Marionette = require('marionette'); + +module.exports = Marionette.ItemView.extend({ + template : 'Settings/Indexers/Delete/IndexerDeleteViewTemplate', + + events : { + 'click .x-confirm-delete' : '_delete' + }, + + _delete : function() { + this.model.destroy({ + wait : true, + success : function() { + vent.trigger(vent.Commands.CloseModalCommand); + } + }); + } +}); \ No newline at end of file diff --git a/src/UI/Settings/NetImport/Delete/IndexerDeleteViewTemplate.hbs b/src/UI/Settings/NetImport/Delete/IndexerDeleteViewTemplate.hbs new file mode 100644 index 000000000..c5c7ad7db --- /dev/null +++ b/src/UI/Settings/NetImport/Delete/IndexerDeleteViewTemplate.hbs @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/src/UI/Settings/NetImport/Edit/IndexerEditView.js b/src/UI/Settings/NetImport/Edit/IndexerEditView.js new file mode 100644 index 000000000..616c863a7 --- /dev/null +++ b/src/UI/Settings/NetImport/Edit/IndexerEditView.js @@ -0,0 +1,122 @@ +var _ = require('underscore'); +var $ = require('jquery'); +var vent = require('vent'); +var Marionette = require('marionette'); +var DeleteView = require('../Delete/IndexerDeleteView'); +var AsModelBoundView = require('../../../Mixins/AsModelBoundView'); +var AsValidatedView = require('../../../Mixins/AsValidatedView'); +var AsEditModalView = require('../../../Mixins/AsEditModalView'); +require('../../../Form/FormBuilder'); +require('../../../Mixins/AutoComplete'); +require('bootstrap'); + +var view = Marionette.ItemView.extend({ + template : 'Settings/Indexers/Edit/IndexerEditViewTemplate', + + events : { + 'click .x-back' : '_back', + 'click .x-captcha-refresh' : '_onRefreshCaptcha' + }, + + _deleteView : DeleteView, + + initialize : function(options) { + this.targetCollection = options.targetCollection; + }, + + _onAfterSave : function() { + this.targetCollection.add(this.model, { merge : true }); + vent.trigger(vent.Commands.CloseModalCommand); + }, + + _onAfterSaveAndAdd : function() { + this.targetCollection.add(this.model, { merge : true }); + + require('../Add/IndexerSchemaModal').open(this.targetCollection); + }, + + _back : function() { + if (this.model.isNew()) { + this.model.destroy(); + } + + require('../Add/IndexerSchemaModal').open(this.targetCollection); + }, + + _onRefreshCaptcha : function(event) { + var self = this; + + var target = $(event.target).parents('.input-group'); + + this.ui.indicator.show(); + + this.model.requestAction("checkCaptcha") + .then(function(result) { + if (!result.captchaRequest) { + self.model.setFieldValue('CaptchaToken', ''); + + return result; + } + + return self._showCaptcha(target, result.captchaRequest); + }) + .always(function() { + self.ui.indicator.hide(); + }); + }, + + _showCaptcha : function(target, captchaRequest) { + var self = this; + + var widget = $('
').insertAfter(target); + + return this._loadRecaptchaWidget(widget[0], captchaRequest.siteKey, captchaRequest.secretToken) + .then(function(captchaResponse) { + target.parents('.form-group').removeAllErrors(); + widget.remove(); + + var queryParams = { + responseUrl : captchaRequest.responseUrl, + ray : captchaRequest.ray, + captchaResponse: captchaResponse + }; + + return self.model.requestAction("getCaptchaCookie", queryParams); + }) + .then(function(response) { + self.model.setFieldValue('CaptchaToken', response.captchaToken); + }); + }, + + _loadRecaptchaWidget : function(widget, sitekey, stoken) { + var promise = $.Deferred(); + + var renderWidget = function() { + window.grecaptcha.render(widget, { + 'sitekey' : sitekey, + 'stoken' : stoken, + 'callback' : promise.resolve + }); + }; + + if (window.grecaptcha) { + renderWidget(); + } else { + window.grecaptchaLoadCallback = function() { + delete window.grecaptchaLoadCallback; + renderWidget(); + }; + + $.getScript('https://www.google.com/recaptcha/api.js?onload=grecaptchaLoadCallback&render=explicit') + .fail(function() { promise.reject(); }); + } + + return promise; + } +}); + +AsModelBoundView.call(view); +AsValidatedView.call(view); +AsEditModalView.call(view); + +module.exports = view; \ No newline at end of file diff --git a/src/UI/Settings/NetImport/Edit/IndexerEditViewTemplate.hbs b/src/UI/Settings/NetImport/Edit/IndexerEditViewTemplate.hbs new file mode 100644 index 000000000..acfb62cbb --- /dev/null +++ b/src/UI/Settings/NetImport/Edit/IndexerEditViewTemplate.hbs @@ -0,0 +1,92 @@ +