diff --git a/frontend/src/Components/Page/Header/MovieSearchInputConnector.js b/frontend/src/Components/Page/Header/MovieSearchInputConnector.js index d0cb96e1a..a44f2128c 100644 --- a/frontend/src/Components/Page/Header/MovieSearchInputConnector.js +++ b/frontend/src/Components/Page/Header/MovieSearchInputConnector.js @@ -1,19 +1,19 @@ import { push } from 'connected-react-router'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector'; +import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector'; import createDeepEqualSelector from 'Store/Selectors/createDeepEqualSelector'; import createTagsSelector from 'Store/Selectors/createTagsSelector'; import MovieSearchInput from './MovieSearchInput'; function createCleanMovieSelector() { return createSelector( - createAllMoviesSelector(), + createAllIndexersSelector(), createTagsSelector(), (allMovies, allTags) => { return allMovies.map((movie) => { const { - title, + name, titleSlug, sortTitle, year, @@ -23,13 +23,13 @@ function createCleanMovieSelector() { } = movie; return { - title, + name, titleSlug, sortTitle, year, images, alternateTitles, - firstCharacter: title.charAt(0).toLowerCase(), + firstCharacter: name.charAt(0).toLowerCase(), tags: tags.reduce((acc, id) => { const matchingTag = allTags.find((tag) => tag.id === id); diff --git a/frontend/src/Indexer/Editor/Delete/DeleteMovieModal.js b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModal.js similarity index 65% rename from frontend/src/Indexer/Editor/Delete/DeleteMovieModal.js rename to frontend/src/Indexer/Editor/Delete/DeleteIndexerModal.js index 8a9a80b16..069e5b7d5 100644 --- a/frontend/src/Indexer/Editor/Delete/DeleteMovieModal.js +++ b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModal.js @@ -1,9 +1,9 @@ import PropTypes from 'prop-types'; import React from 'react'; import Modal from 'Components/Modal/Modal'; -import DeleteMovieModalContentConnector from './DeleteMovieModalContentConnector'; +import DeleteIndexerModalContentConnector from './DeleteIndexerModalContentConnector'; -function DeleteMovieModal(props) { +function DeleteIndexerModal(props) { const { isOpen, onModalClose, @@ -15,7 +15,7 @@ function DeleteMovieModal(props) { isOpen={isOpen} onModalClose={onModalClose} > - @@ -23,9 +23,9 @@ function DeleteMovieModal(props) { ); } -DeleteMovieModal.propTypes = { +DeleteIndexerModal.propTypes = { isOpen: PropTypes.bool.isRequired, onModalClose: PropTypes.func.isRequired }; -export default DeleteMovieModal; +export default DeleteIndexerModal; diff --git a/frontend/src/Indexer/Editor/Delete/DeleteMovieModalContent.css b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.css similarity index 100% rename from frontend/src/Indexer/Editor/Delete/DeleteMovieModalContent.css rename to frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.css diff --git a/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.js b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.js new file mode 100644 index 000000000..dff05e52d --- /dev/null +++ b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContent.js @@ -0,0 +1,74 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Button from 'Components/Link/Button'; +import ModalBody from 'Components/Modal/ModalBody'; +import ModalContent from 'Components/Modal/ModalContent'; +import ModalFooter from 'Components/Modal/ModalFooter'; +import ModalHeader from 'Components/Modal/ModalHeader'; +import { kinds } from 'Helpers/Props'; +import translate from 'Utilities/String/translate'; +import styles from './DeleteIndexerModalContent.css'; + +class DeleteIndexerModalContent extends Component { + onDeleteMovieConfirmed = () => { + this.props.onDeleteSelectedPress(); + } + + // + // Render + + render() { + const { + indexers, + onModalClose + } = this.props; + + return ( + + + Delete Selected Indexers(s) + + + + +
+ {`Are you sure you want to delete ${indexers.length} selected indexers(s)`} +
+ +
    + { + indexers.map((s) => { + return ( +
  • + {s.name} +
  • + ); + }) + } +
+
+ + + + + + +
+ ); + } +} + +DeleteIndexerModalContent.propTypes = { + indexers: PropTypes.arrayOf(PropTypes.object).isRequired, + onModalClose: PropTypes.func.isRequired, + onDeleteSelectedPress: PropTypes.func.isRequired +}; + +export default DeleteIndexerModalContent; diff --git a/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContentConnector.js b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContentConnector.js new file mode 100644 index 000000000..be199a65b --- /dev/null +++ b/frontend/src/Indexer/Editor/Delete/DeleteIndexerModalContentConnector.js @@ -0,0 +1,43 @@ +import _ from 'lodash'; +import { connect } from 'react-redux'; +import { createSelector } from 'reselect'; +import { bulkDeleteIndexers } from 'Store/Actions/indexerIndexActions'; +import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector'; +import DeleteIndexerModalContent from './DeleteIndexerModalContent'; + +function createMapStateToProps() { + return createSelector( + (state, { indexerIds }) => indexerIds, + createAllIndexersSelector(), + (indexerIds, allIndexers) => { + const selectedMovie = _.intersectionWith(allIndexers, indexerIds, (s, id) => { + return s.id === id; + }); + + const sortedMovies = _.orderBy(selectedMovie, 'name'); + const indexers = _.map(sortedMovies, (s) => { + return { + name: s.name + }; + }); + + return { + indexers + }; + } + ); +} + +function createMapDispatchToProps(dispatch, props) { + return { + onDeleteSelectedPress() { + dispatch(bulkDeleteIndexers({ + indexerIds: props.indexerIds + })); + + props.onModalClose(); + } + }; +} + +export default connect(createMapStateToProps, createMapDispatchToProps)(DeleteIndexerModalContent); diff --git a/frontend/src/Indexer/Editor/Delete/DeleteMovieModalContent.js b/frontend/src/Indexer/Editor/Delete/DeleteMovieModalContent.js deleted file mode 100644 index eeb434789..000000000 --- a/frontend/src/Indexer/Editor/Delete/DeleteMovieModalContent.js +++ /dev/null @@ -1,145 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import FormGroup from 'Components/Form/FormGroup'; -import FormInputGroup from 'Components/Form/FormInputGroup'; -import FormLabel from 'Components/Form/FormLabel'; -import Button from 'Components/Link/Button'; -import ModalBody from 'Components/Modal/ModalBody'; -import ModalContent from 'Components/Modal/ModalContent'; -import ModalFooter from 'Components/Modal/ModalFooter'; -import ModalHeader from 'Components/Modal/ModalHeader'; -import { inputTypes, kinds } from 'Helpers/Props'; -import translate from 'Utilities/String/translate'; -import styles from './DeleteMovieModalContent.css'; - -class DeleteMovieModalContent extends Component { - - // - // Lifecycle - - constructor(props, context) { - super(props, context); - - this.state = { - deleteFiles: false, - addImportExclusion: false - }; - } - - // - // Listeners - - onDeleteFilesChange = ({ value }) => { - this.setState({ deleteFiles: value }); - } - - onAddImportExclusionChange = ({ value }) => { - this.setState({ addImportExclusion: value }); - } - - onDeleteMovieConfirmed = () => { - const deleteFiles = this.state.deleteFiles; - const addImportExclusion = this.state.addImportExclusion; - - this.setState({ deleteFiles: false, addImportExclusion: false }); - this.props.onDeleteSelectedPress(deleteFiles, addImportExclusion); - } - - // - // Render - - render() { - const { - movies, - onModalClose - } = this.props; - - const deleteFiles = this.state.deleteFiles; - const addImportExclusion = this.state.addImportExclusion; - - return ( - - - Delete Selected Movie(s) - - - -
- - {`Delete Movie Folder${movies.length > 1 ? 's' : ''}`} - - 1 ? 's' : ''} and all contents`} - kind={kinds.DANGER} - onChange={this.onDeleteFilesChange} - /> - - - - {translate('AddListExclusion')} - - - -
- -
- {`Are you sure you want to delete ${movies.length} selected movie(s)${deleteFiles ? ' and all contents' : ''}?`} -
- -
    - { - movies.map((s) => { - return ( -
  • - {s.title} - - { - deleteFiles && - - - - - {s.path} - - - } -
  • - ); - }) - } -
-
- - - - - - -
- ); - } -} - -DeleteMovieModalContent.propTypes = { - movies: PropTypes.arrayOf(PropTypes.object).isRequired, - onModalClose: PropTypes.func.isRequired, - onDeleteSelectedPress: PropTypes.func.isRequired -}; - -export default DeleteMovieModalContent; diff --git a/frontend/src/Indexer/Editor/Delete/DeleteMovieModalContentConnector.js b/frontend/src/Indexer/Editor/Delete/DeleteMovieModalContentConnector.js deleted file mode 100644 index 7bb7d3bf3..000000000 --- a/frontend/src/Indexer/Editor/Delete/DeleteMovieModalContentConnector.js +++ /dev/null @@ -1,46 +0,0 @@ -import _ from 'lodash'; -import { connect } from 'react-redux'; -import { createSelector } from 'reselect'; -import { bulkDeleteMovie } from 'Store/Actions/indexerIndexActions'; -import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector'; -import DeleteMovieModalContent from './DeleteMovieModalContent'; - -function createMapStateToProps() { - return createSelector( - (state, { movieIds }) => movieIds, - createAllMoviesSelector(), - (movieIds, allMovies) => { - const selectedMovie = _.intersectionWith(allMovies, movieIds, (s, id) => { - return s.id === id; - }); - - const sortedMovies = _.orderBy(selectedMovie, 'sortTitle'); - const movies = _.map(sortedMovies, (s) => { - return { - title: s.title, - path: s.path - }; - }); - - return { - movies - }; - } - ); -} - -function createMapDispatchToProps(dispatch, props) { - return { - onDeleteSelectedPress(deleteFiles, addImportExclusion) { - dispatch(bulkDeleteMovie({ - movieIds: props.movieIds, - deleteFiles, - addImportExclusion - })); - - props.onModalClose(); - } - }; -} - -export default connect(createMapStateToProps, createMapDispatchToProps)(DeleteMovieModalContent); diff --git a/frontend/src/Indexer/Editor/MovieEditorFooter.css b/frontend/src/Indexer/Editor/IndexerEditorFooter.css similarity index 100% rename from frontend/src/Indexer/Editor/MovieEditorFooter.css rename to frontend/src/Indexer/Editor/IndexerEditorFooter.css diff --git a/frontend/src/Indexer/Editor/MovieEditorFooter.js b/frontend/src/Indexer/Editor/IndexerEditorFooter.js similarity index 87% rename from frontend/src/Indexer/Editor/MovieEditorFooter.js rename to frontend/src/Indexer/Editor/IndexerEditorFooter.js index 690242be6..7a9f2bff1 100644 --- a/frontend/src/Indexer/Editor/MovieEditorFooter.js +++ b/frontend/src/Indexer/Editor/IndexerEditorFooter.js @@ -4,14 +4,14 @@ import SpinnerButton from 'Components/Link/SpinnerButton'; import PageContentFooter from 'Components/Page/PageContentFooter'; import { kinds } from 'Helpers/Props'; import translate from 'Utilities/String/translate'; -import DeleteMovieModal from './Delete/DeleteMovieModal'; -import MovieEditorFooterLabel from './MovieEditorFooterLabel'; +import DeleteIndexerModal from './Delete/DeleteIndexerModal'; +import IndexerEditorFooterLabel from './IndexerEditorFooterLabel'; import TagsModal from './Tags/TagsModal'; -import styles from './MovieEditorFooter.css'; +import styles from './IndexerEditorFooter.css'; const NO_CHANGE = 'noChange'; -class MovieEditorFooter extends Component { +class IndexerEditorFooter extends Component { // // Lifecycle @@ -88,7 +88,7 @@ class MovieEditorFooter extends Component { render() { const { - movieIds, + indexerIds, selectedCount, isSaving, isDeleting @@ -104,7 +104,7 @@ class MovieEditorFooter extends Component {
- @@ -136,14 +136,14 @@ class MovieEditorFooter extends Component { - @@ -151,8 +151,8 @@ class MovieEditorFooter extends Component { } } -MovieEditorFooter.propTypes = { - movieIds: PropTypes.arrayOf(PropTypes.number).isRequired, +IndexerEditorFooter.propTypes = { + indexerIds: PropTypes.arrayOf(PropTypes.number).isRequired, selectedCount: PropTypes.number.isRequired, isSaving: PropTypes.bool.isRequired, saveError: PropTypes.object, @@ -161,4 +161,4 @@ MovieEditorFooter.propTypes = { onSaveSelected: PropTypes.func.isRequired }; -export default MovieEditorFooter; +export default IndexerEditorFooter; diff --git a/frontend/src/Indexer/Editor/MovieEditorFooterLabel.css b/frontend/src/Indexer/Editor/IndexerEditorFooterLabel.css similarity index 100% rename from frontend/src/Indexer/Editor/MovieEditorFooterLabel.css rename to frontend/src/Indexer/Editor/IndexerEditorFooterLabel.css diff --git a/frontend/src/Indexer/Editor/MovieEditorFooterLabel.js b/frontend/src/Indexer/Editor/IndexerEditorFooterLabel.js similarity index 74% rename from frontend/src/Indexer/Editor/MovieEditorFooterLabel.js rename to frontend/src/Indexer/Editor/IndexerEditorFooterLabel.js index 805ecd39e..e498d1480 100644 --- a/frontend/src/Indexer/Editor/MovieEditorFooterLabel.js +++ b/frontend/src/Indexer/Editor/IndexerEditorFooterLabel.js @@ -2,9 +2,9 @@ import PropTypes from 'prop-types'; import React from 'react'; import SpinnerIcon from 'Components/SpinnerIcon'; import { icons } from 'Helpers/Props'; -import styles from './MovieEditorFooterLabel.css'; +import styles from './IndexerEditorFooterLabel.css'; -function MovieEditorFooterLabel(props) { +function IndexerEditorFooterLabel(props) { const { className, label, @@ -27,14 +27,14 @@ function MovieEditorFooterLabel(props) { ); } -MovieEditorFooterLabel.propTypes = { +IndexerEditorFooterLabel.propTypes = { className: PropTypes.string.isRequired, label: PropTypes.string.isRequired, isSaving: PropTypes.bool.isRequired }; -MovieEditorFooterLabel.defaultProps = { +IndexerEditorFooterLabel.defaultProps = { className: styles.label }; -export default MovieEditorFooterLabel; +export default IndexerEditorFooterLabel; diff --git a/frontend/src/Indexer/Editor/Tags/TagsModalContentConnector.js b/frontend/src/Indexer/Editor/Tags/TagsModalContentConnector.js index 75d2006d4..8b7d74f50 100644 --- a/frontend/src/Indexer/Editor/Tags/TagsModalContentConnector.js +++ b/frontend/src/Indexer/Editor/Tags/TagsModalContentConnector.js @@ -1,17 +1,17 @@ import _ from 'lodash'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; -import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector'; +import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector'; import createTagsSelector from 'Store/Selectors/createTagsSelector'; import TagsModalContent from './TagsModalContent'; function createMapStateToProps() { return createSelector( - (state, { movieIds }) => movieIds, - createAllMoviesSelector(), + (state, { indexerIds }) => indexerIds, + createAllIndexersSelector(), createTagsSelector(), - (movieIds, allMovies, tagList) => { - const movies = _.intersectionWith(allMovies, movieIds, (s, id) => { + (indexerIds, allMovies, tagList) => { + const movies = _.intersectionWith(allMovies, indexerIds, (s, id) => { return s.id === id; }); diff --git a/frontend/src/Indexer/Index/IndexerIndex.js b/frontend/src/Indexer/Index/IndexerIndex.js index 956c3b2c7..a10e1f74d 100644 --- a/frontend/src/Indexer/Index/IndexerIndex.js +++ b/frontend/src/Indexer/Index/IndexerIndex.js @@ -11,7 +11,7 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection'; import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import { align, icons, sortDirections } from 'Helpers/Props'; -import MovieEditorFooter from 'Indexer/Editor/MovieEditorFooter.js'; +import IndexerEditorFooter from 'Indexer/Editor/IndexerEditorFooter.js'; import NoIndexer from 'Indexer/NoIndexer'; import AddIndexerModal from 'Settings/Indexers/Indexers/AddIndexerModal'; import EditIndexerModalConnector from 'Settings/Indexers/Indexers/EditIndexerModalConnector'; @@ -444,8 +444,8 @@ class IndexerIndex extends Component { { isLoaded && isMovieEditorActive && - movieIds, - createAllMoviesSelector(), + (state, { indexerIds }) => indexerIds, + createAllIndexersSelector(), findMatchingItems ); } @@ -37,14 +37,6 @@ function createMatchingMoviesSelector() { ); } -function createMatchingDelayProfilesSelector() { - return createSelector( - (state, { delayProfileIds }) => delayProfileIds, - (state) => state.settings.delayProfiles.items, - findMatchingItems - ); -} - function createMatchingNotificationsSelector() { return createSelector( (state, { notificationIds }) => notificationIds, @@ -53,26 +45,14 @@ function createMatchingNotificationsSelector() { ); } -function createMatchingRestrictionsSelector() { - return createSelector( - (state, { restrictionIds }) => restrictionIds, - (state) => state.settings.restrictions.items, - findMatchingItems - ); -} - function createMapStateToProps() { return createSelector( createMatchingMoviesSelector(), - createMatchingDelayProfilesSelector(), createMatchingNotificationsSelector(), - createMatchingRestrictionsSelector(), - (movies, delayProfiles, notifications, restrictions) => { + (movies, notifications) => { return { movies, - delayProfiles, - notifications, - restrictions + notifications }; } ); diff --git a/frontend/src/Store/Actions/indexerIndexActions.js b/frontend/src/Store/Actions/indexerIndexActions.js index 5317d70d5..8bd6a62b0 100644 --- a/frontend/src/Store/Actions/indexerIndexActions.js +++ b/frontend/src/Store/Actions/indexerIndexActions.js @@ -4,7 +4,7 @@ import { filterBuilderTypes, filterBuilderValueTypes, sortDirections } from 'Hel import { createThunk, handleThunks } from 'Store/thunks'; import createAjaxRequest from 'Utilities/createAjaxRequest'; import translate from 'Utilities/String/translate'; -import { set, updateItem } from './baseActions'; +import { removeItem, set, updateItem } from './baseActions'; import createHandleActions from './Creators/createHandleActions'; import createSetClientSideCollectionFilterReducer from './Creators/Reducers/createSetClientSideCollectionFilterReducer'; import createSetClientSideCollectionSortReducer from './Creators/Reducers/createSetClientSideCollectionSortReducer'; @@ -24,9 +24,9 @@ export const defaultState = { saveError: null, isDeleting: false, deleteError: null, - sortKey: 'sortTitle', + sortKey: 'name', sortDirection: sortDirections.ASCENDING, - secondarySortKey: 'sortTitle', + secondarySortKey: 'name', secondarySortDirection: sortDirections.ASCENDING, tableOptions: { @@ -105,7 +105,7 @@ export const defaultState = { filterBuilderProps: [ { - name: 'title', + name: 'name', label: 'Indexer Name', type: filterBuilderTypes.STRING }, @@ -142,7 +142,7 @@ export const SET_MOVIE_FILTER = 'indexerIndex/setMovieFilter'; export const SET_MOVIE_VIEW = 'indexerIndex/setMovieView'; export const SET_MOVIE_TABLE_OPTION = 'indexerIndex/setMovieTableOption'; export const SAVE_MOVIE_EDITOR = 'indexerIndex/saveMovieEditor'; -export const BULK_DELETE_MOVIE = 'indexerIndex/bulkDeleteMovie'; +export const BULK_DELETE_INDEXERS = 'indexerIndex/bulkDeleteIndexers'; // // Action Creators @@ -152,7 +152,7 @@ export const setMovieFilter = createAction(SET_MOVIE_FILTER); export const setMovieView = createAction(SET_MOVIE_VIEW); export const setMovieTableOption = createAction(SET_MOVIE_TABLE_OPTION); export const saveMovieEditor = createThunk(SAVE_MOVIE_EDITOR); -export const bulkDeleteMovie = createThunk(BULK_DELETE_MOVIE); +export const bulkDeleteIndexers = createThunk(BULK_DELETE_INDEXERS); // // Action Handlers @@ -198,27 +198,31 @@ export const actionHandlers = handleThunks({ }); }, - [BULK_DELETE_MOVIE]: function(getState, payload, dispatch) { + [BULK_DELETE_INDEXERS]: function(getState, payload, dispatch) { dispatch(set({ section, isDeleting: true })); const promise = createAjaxRequest({ - url: '/movie/editor', + url: '/indexer/editor', method: 'DELETE', data: JSON.stringify(payload), dataType: 'json' }).request; promise.done(() => { - // SignaR will take care of removing the movie from the collection + dispatch(batchActions([ + ...payload.indexerIds.map((id) => { + return removeItem({ section: 'indexers', id }); + }), - dispatch(set({ - section, - isDeleting: false, - deleteError: null - })); + set({ + section, + isDeleting: false, + deleteError: null + }) + ])); }); promise.fail((xhr) => { diff --git a/frontend/src/Store/Selectors/createAllIndexersSelector.js b/frontend/src/Store/Selectors/createAllIndexersSelector.js new file mode 100644 index 000000000..178c54eed --- /dev/null +++ b/frontend/src/Store/Selectors/createAllIndexersSelector.js @@ -0,0 +1,12 @@ +import { createSelector } from 'reselect'; + +function createAllIndexersSelector() { + return createSelector( + (state) => state.indexers, + (indexers) => { + return indexers.items; + } + ); +} + +export default createAllIndexersSelector; diff --git a/frontend/src/Store/Selectors/createAllMoviesSelector.js b/frontend/src/Store/Selectors/createAllMoviesSelector.js deleted file mode 100644 index a6bad0991..000000000 --- a/frontend/src/Store/Selectors/createAllMoviesSelector.js +++ /dev/null @@ -1,12 +0,0 @@ -import { createSelector } from 'reselect'; - -function createAllMoviesSelector() { - return createSelector( - (state) => state.movies, - (movies) => { - return movies.items; - } - ); -} - -export default createAllMoviesSelector; diff --git a/src/NzbDrone.Core/Indexers/IndexerFactory.cs b/src/NzbDrone.Core/Indexers/IndexerFactory.cs index b8f4187f4..8db47837b 100644 --- a/src/NzbDrone.Core/Indexers/IndexerFactory.cs +++ b/src/NzbDrone.Core/Indexers/IndexerFactory.cs @@ -14,6 +14,7 @@ namespace NzbDrone.Core.Indexers List RssEnabled(bool filterBlockedIndexers = true); List AutomaticSearchEnabled(bool filterBlockedIndexers = true); List InteractiveSearchEnabled(bool filterBlockedIndexers = true); + void DeleteIndexers(List indexerIds); } public class IndexerFactory : ProviderFactory, IIndexerFactory @@ -102,6 +103,18 @@ namespace NzbDrone.Core.Indexers } } + public void DeleteIndexers(List indexerIds) + { + var indexersToDelete = _providerRepository.Get(indexerIds).ToList(); + + _providerRepository.DeleteMany(indexerIds); + + foreach (var indexer in indexersToDelete) + { + _logger.Info("Deleted indexer {0}", indexer.Name); + } + } + public override ValidationResult Test(IndexerDefinition definition) { var result = base.Test(definition); diff --git a/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs b/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs index b37aefda9..60dbc8e99 100644 --- a/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs +++ b/src/NzbDrone.Core/ThingiProvider/ProviderFactory.cs @@ -14,7 +14,7 @@ namespace NzbDrone.Core.ThingiProvider where TProviderDefinition : ProviderDefinition, new() where TProvider : IProvider { - private readonly IProviderRepository _providerRepository; + protected readonly IProviderRepository _providerRepository; private readonly IContainer _container; private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; diff --git a/src/Prowlarr.Api.V1/FileSystem/FileSystemModule.cs b/src/Prowlarr.Api.V1/FileSystem/FileSystemModule.cs index 695bdff4d..332533bb2 100644 --- a/src/Prowlarr.Api.V1/FileSystem/FileSystemModule.cs +++ b/src/Prowlarr.Api.V1/FileSystem/FileSystemModule.cs @@ -8,7 +8,7 @@ using Prowlarr.Http.Extensions; namespace Prowlarr.Api.V1.FileSystem { - public class FileSystemModule : ProwlarrV3Module + public class FileSystemModule : ProwlarrV1Module { private readonly IFileSystemLookupService _fileSystemLookupService; private readonly IDiskProvider _diskProvider; diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerEditorModule.cs b/src/Prowlarr.Api.V1/Indexers/IndexerEditorModule.cs new file mode 100644 index 000000000..4f0864de6 --- /dev/null +++ b/src/Prowlarr.Api.V1/Indexers/IndexerEditorModule.cs @@ -0,0 +1,30 @@ +using Nancy; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Messaging.Commands; +using Prowlarr.Http.Extensions; + +namespace Prowlarr.Api.V1.Indexers +{ + public class IndexerEditorModule : ProwlarrV1Module + { + private readonly IIndexerFactory _movieService; + private readonly IManageCommandQueue _commandQueueManager; + + public IndexerEditorModule(IIndexerFactory movieService, IManageCommandQueue commandQueueManager) + : base("/indexer/editor") + { + _movieService = movieService; + _commandQueueManager = commandQueueManager; + Delete("/", movie => DeleteIndexers()); + } + + private object DeleteIndexers() + { + var resource = Request.Body.FromJson(); + + _movieService.DeleteIndexers(resource.IndexerIds); + + return new object(); + } + } +} diff --git a/src/Prowlarr.Api.V1/Indexers/IndexerEditorResource.cs b/src/Prowlarr.Api.V1/Indexers/IndexerEditorResource.cs new file mode 100644 index 000000000..569cbf067 --- /dev/null +++ b/src/Prowlarr.Api.V1/Indexers/IndexerEditorResource.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Prowlarr.Api.V1.Indexers +{ + public class IndexerEditorResource + { + public List IndexerIds { get; set; } + } +} diff --git a/src/Prowlarr.Api.V1/ProwlarrV1Module.cs b/src/Prowlarr.Api.V1/ProwlarrV1Module.cs index b9eb66001..dd814a461 100644 --- a/src/Prowlarr.Api.V1/ProwlarrV1Module.cs +++ b/src/Prowlarr.Api.V1/ProwlarrV1Module.cs @@ -2,9 +2,9 @@ using Prowlarr.Http; namespace Prowlarr.Api.V1 { - public abstract class ProwlarrV3Module : ProwlarrModule + public abstract class ProwlarrV1Module : ProwlarrModule { - protected ProwlarrV3Module(string resource) + protected ProwlarrV1Module(string resource) : base("/api/v1/" + resource.Trim('/')) { } diff --git a/src/Prowlarr.Api.V1/System/SystemModule.cs b/src/Prowlarr.Api.V1/System/SystemModule.cs index 750b0417f..6753d84a3 100644 --- a/src/Prowlarr.Api.V1/System/SystemModule.cs +++ b/src/Prowlarr.Api.V1/System/SystemModule.cs @@ -8,7 +8,7 @@ using NzbDrone.Core.Lifecycle; namespace Prowlarr.Api.V1.System { - public class SystemModule : ProwlarrV3Module + public class SystemModule : ProwlarrV1Module { private readonly IAppFolderInfo _appFolderInfo; private readonly IRuntimeInfo _runtimeInfo;