From aef8a8fd0452282e983ec301f263c2df22e751be Mon Sep 17 00:00:00 2001 From: Qstick Date: Sun, 27 Sep 2020 23:08:20 -0400 Subject: [PATCH] Fixed: Fetch blacklist by Movie instead of all Fixes #5066 --- .../InteractiveSearchRowConnector.js | 6 +- .../Movie/Details/MovieDetailsConnector.js | 20 ++--- frontend/src/Store/Actions/index.js | 2 + .../Store/Actions/movieBlacklistActions.js | 82 +++++++++++++++++++ .../BlacklistRepositoryFixture.cs | 4 +- .../Blacklisting/BlacklistRepository.cs | 6 +- .../Blacklisting/BlacklistService.cs | 6 ++ .../CustomFormatCalculationService.cs | 7 +- .../Blacklist/BlacklistModule.cs | 20 +++++ 9 files changed, 132 insertions(+), 21 deletions(-) create mode 100644 frontend/src/Store/Actions/movieBlacklistActions.js diff --git a/frontend/src/InteractiveSearch/InteractiveSearchRowConnector.js b/frontend/src/InteractiveSearch/InteractiveSearchRowConnector.js index d8c816957..a8d6c6702 100644 --- a/frontend/src/InteractiveSearch/InteractiveSearchRowConnector.js +++ b/frontend/src/InteractiveSearch/InteractiveSearchRowConnector.js @@ -8,8 +8,8 @@ function createMapStateToProps() { return createSelector( (state, { guid }) => guid, (state) => state.movieHistory.items, - (state) => state.blacklist.items, - (guid, movieHistory, blacklist) => { + (state) => state.movieBlacklist.items, + (guid, movieHistory, movieBlacklist) => { let blacklistData = {}; let historyFailedData = {}; @@ -17,7 +17,7 @@ function createMapStateToProps() { const historyGrabbedData = movieHistory.find((movie) => movie.eventType === 'grabbed' && movie.data.guid === guid); if (historyGrabbedData) { historyFailedData = movieHistory.find((movie) => movie.eventType === 'downloadFailed' && movie.sourceTitle === historyGrabbedData.sourceTitle); - blacklistData = blacklist.find((item) => item.sourceTitle === historyGrabbedData.sourceTitle); + blacklistData = movieBlacklist.find((item) => item.sourceTitle === historyGrabbedData.sourceTitle); } return { diff --git a/frontend/src/Movie/Details/MovieDetailsConnector.js b/frontend/src/Movie/Details/MovieDetailsConnector.js index fdbc65af8..2ab6b9167 100644 --- a/frontend/src/Movie/Details/MovieDetailsConnector.js +++ b/frontend/src/Movie/Details/MovieDetailsConnector.js @@ -5,10 +5,10 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import * as commandNames from 'Commands/commandNames'; -import { fetchBlacklist } from 'Store/Actions/blacklistActions'; import { executeCommand } from 'Store/Actions/commandActions'; import { clearExtraFiles, fetchExtraFiles } from 'Store/Actions/extraFileActions'; import { toggleMovieMonitored } from 'Store/Actions/movieActions'; +import { clearMovieBlacklist, fetchMovieBlacklist } from 'Store/Actions/movieBlacklistActions'; import { clearMovieCredits, fetchMovieCredits } from 'Store/Actions/movieCreditsActions'; import { clearMovieFiles, fetchMovieFiles } from 'Store/Actions/movieFileActions'; import { clearMovieHistory, fetchMovieHistory } from 'Store/Actions/movieHistoryActions'; @@ -222,9 +222,11 @@ function createMapDispatchToProps(dispatch, props) { onGoToMovie(titleSlug) { dispatch(push(`${window.Radarr.urlBase}/movie/${titleSlug}`)); }, - dispatchFetchBlacklist() { - // TODO: Allow for passing a movie id to fetch a single movie's blacklist data - dispatch(fetchBlacklist()); + dispatchFetchMovieBlacklist({ movieId }) { + dispatch(fetchMovieBlacklist({ movieId })); + }, + dispatchClearMovieBlacklist() { + dispatch(clearMovieBlacklist()); } }; } @@ -278,20 +280,17 @@ class MovieDetailsConnector extends Component { const movieId = this.props.id; this.props.dispatchFetchMovieFiles({ movieId }); + this.props.dispatchFetchMovieBlacklist({ movieId }); this.props.dispatchFetchMovieHistory({ movieId }); this.props.dispatchFetchExtraFiles({ movieId }); this.props.dispatchFetchMovieCredits({ movieId }); this.props.dispatchFetchQueueDetails({ movieId }); this.props.dispatchFetchImportListSchema(); - this.props.dispatchFetchBlacklist(); - } - - repopulate = () => { - this.props.dispatchFetchBlacklist(); } unpopulate = () => { this.props.dispatchCancelFetchReleases(); + this.props.dispatchClearMovieBlacklist(); this.props.dispatchClearMovieFiles(); this.props.dispatchClearMovieHistory(); this.props.dispatchClearExtraFiles(); @@ -363,7 +362,8 @@ MovieDetailsConnector.propTypes = { dispatchClearQueueDetails: PropTypes.func.isRequired, dispatchFetchImportListSchema: PropTypes.func.isRequired, dispatchExecuteCommand: PropTypes.func.isRequired, - dispatchFetchBlacklist: PropTypes.func.isRequired, + dispatchFetchMovieBlacklist: PropTypes.func.isRequired, + dispatchClearMovieBlacklist: PropTypes.func.isRequired, onGoToMovie: PropTypes.func.isRequired }; diff --git a/frontend/src/Store/Actions/index.js b/frontend/src/Store/Actions/index.js index ab70482d8..21c6123a3 100644 --- a/frontend/src/Store/Actions/index.js +++ b/frontend/src/Store/Actions/index.js @@ -11,6 +11,7 @@ import * as history from './historyActions'; import * as importMovie from './importMovieActions'; import * as interactiveImportActions from './interactiveImportActions'; import * as movies from './movieActions'; +import * as movieBlacklist from './movieBlacklistActions'; import * as movieCredits from './movieCreditsActions'; import * as movieFiles from './movieFileActions'; import * as movieHistory from './movieHistoryActions'; @@ -48,6 +49,7 @@ export default [ releases, rootFolders, movies, + movieBlacklist, movieHistory, movieIndex, movieCredits, diff --git a/frontend/src/Store/Actions/movieBlacklistActions.js b/frontend/src/Store/Actions/movieBlacklistActions.js new file mode 100644 index 000000000..08c3c2baf --- /dev/null +++ b/frontend/src/Store/Actions/movieBlacklistActions.js @@ -0,0 +1,82 @@ +import { createAction } from 'redux-actions'; +import { batchActions } from 'redux-batched-actions'; +import { createThunk, handleThunks } from 'Store/thunks'; +import createAjaxRequest from 'Utilities/createAjaxRequest'; +import { set, update } from './baseActions'; +import createHandleActions from './Creators/createHandleActions'; + +// +// Variables + +export const section = 'movieBlacklist'; + +// +// State + +export const defaultState = { + isFetching: false, + isPopulated: false, + error: null, + items: [] +}; + +// +// Actions Types + +export const FETCH_MOVIE_BLACKLIST = 'movieBlacklist/fetchMovieBlacklist'; +export const CLEAR_MOVIE_BLACKLIST = 'movieBlacklist/clearMovieBlacklist'; + +// +// Action Creators + +export const fetchMovieBlacklist = createThunk(FETCH_MOVIE_BLACKLIST); +export const clearMovieBlacklist = createAction(CLEAR_MOVIE_BLACKLIST); + +// +// Action Handlers + +export const actionHandlers = handleThunks({ + + [FETCH_MOVIE_BLACKLIST]: function(getState, payload, dispatch) { + dispatch(set({ section, isFetching: true })); + + const promise = createAjaxRequest({ + url: '/blacklist/movie', + data: payload + }).request; + + promise.done((data) => { + dispatch(batchActions([ + update({ section, data }), + + set({ + section, + isFetching: false, + isPopulated: true, + error: null + }) + ])); + }); + + promise.fail((xhr) => { + dispatch(set({ + section, + isFetching: false, + isPopulated: false, + error: xhr + })); + }); + } +}); + +// +// Reducers + +export const reducers = createHandleActions({ + + [CLEAR_MOVIE_BLACKLIST]: (state) => { + return Object.assign({}, state, defaultState); + } + +}, defaultState, section); + diff --git a/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs b/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs index 9e09215be..49912d890 100644 --- a/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs +++ b/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs @@ -81,8 +81,8 @@ namespace NzbDrone.Core.Test.Blacklisting Subject.DeleteForMovies(new List { _movie1.Id }); - var removedMovieBlacklists = Subject.BlacklistedByMovies(new List { _movie1.Id }); - var nonRemovedMovieBlacklists = Subject.BlacklistedByMovies(new List { _movie2.Id }); + var removedMovieBlacklists = Subject.BlacklistedByMovie(_movie1.Id); + var nonRemovedMovieBlacklists = Subject.BlacklistedByMovie(_movie2.Id); removedMovieBlacklists.Should().HaveCount(0); nonRemovedMovieBlacklists.Should().HaveCount(1); diff --git a/src/NzbDrone.Core/Blacklisting/BlacklistRepository.cs b/src/NzbDrone.Core/Blacklisting/BlacklistRepository.cs index 6dc0f6809..a5b623f0c 100644 --- a/src/NzbDrone.Core/Blacklisting/BlacklistRepository.cs +++ b/src/NzbDrone.Core/Blacklisting/BlacklistRepository.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Core.Blacklisting { List BlacklistedByTitle(int movieId, string sourceTitle); List BlacklistedByTorrentInfoHash(int movieId, string torrentInfoHash); - List BlacklistedByMovies(List movieIds); + List BlacklistedByMovie(int movieId); void DeleteForMovies(List movieIds); } @@ -30,9 +30,9 @@ namespace NzbDrone.Core.Blacklisting return Query(x => x.MovieId == movieId && x.TorrentInfoHash.Contains(torrentInfoHash)); } - public List BlacklistedByMovies(List movieIds) + public List BlacklistedByMovie(int movieId) { - return Query(x => movieIds.Contains(x.MovieId)); + return Query(x => x.MovieId == movieId); } public void DeleteForMovies(List movieIds) diff --git a/src/NzbDrone.Core/Blacklisting/BlacklistService.cs b/src/NzbDrone.Core/Blacklisting/BlacklistService.cs index 5209d370b..a0dd0a805 100644 --- a/src/NzbDrone.Core/Blacklisting/BlacklistService.cs +++ b/src/NzbDrone.Core/Blacklisting/BlacklistService.cs @@ -16,6 +16,7 @@ namespace NzbDrone.Core.Blacklisting { bool Blacklisted(int movieId, ReleaseInfo release); PagingSpec Paged(PagingSpec pagingSpec); + List GetByMovieId(int movieId); void Delete(int id); } @@ -65,6 +66,11 @@ namespace NzbDrone.Core.Blacklisting return _blacklistRepository.GetPaged(pagingSpec); } + public List GetByMovieId(int movieId) + { + return _blacklistRepository.BlacklistedByMovie(movieId); + } + public void Delete(int id) { _blacklistRepository.Delete(id); diff --git a/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs b/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs index e58dedea6..c60685cdb 100644 --- a/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs +++ b/src/NzbDrone.Core/CustomFormats/CustomFormatCalculationService.cs @@ -107,18 +107,19 @@ namespace NzbDrone.Core.CustomFormats public List ParseCustomFormat(Blacklist blacklist) { + var movie = _movieService.GetMovie(blacklist.MovieId); var parsed = _parsingService.ParseMovieInfo(blacklist.SourceTitle, null); var info = new ParsedMovieInfo { - MovieTitle = blacklist.Movie.Title, + MovieTitle = movie.Title, SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? blacklist.SourceTitle.SimplifyReleaseTitle(), Quality = blacklist.Quality, Languages = blacklist.Languages, ReleaseGroup = parsed?.ReleaseGroup, Edition = parsed?.Edition, - Year = blacklist.Movie.Year, - ImdbId = blacklist.Movie.ImdbId, + Year = movie.Year, + ImdbId = movie.ImdbId, ExtraInfo = new Dictionary { { "IndexerFlags", blacklist.IndexerFlags }, diff --git a/src/Radarr.Api.V3/Blacklist/BlacklistModule.cs b/src/Radarr.Api.V3/Blacklist/BlacklistModule.cs index 30078d564..99c52a8cb 100644 --- a/src/Radarr.Api.V3/Blacklist/BlacklistModule.cs +++ b/src/Radarr.Api.V3/Blacklist/BlacklistModule.cs @@ -1,7 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; using NzbDrone.Core.Blacklisting; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Datastore; using Radarr.Http; +using Radarr.Http.REST; namespace Radarr.Api.V3.Blacklist { @@ -18,6 +22,8 @@ namespace Radarr.Api.V3.Blacklist GetResourcePaged = GetBlacklist; DeleteResource = DeleteBlacklist; + + Get("/movie", x => GetMovieBlacklist()); } private PagingResource GetBlacklist(PagingResource pagingResource) @@ -27,6 +33,20 @@ namespace Radarr.Api.V3.Blacklist return ApplyToPage(_blacklistService.Paged, pagingSpec, (blacklist) => BlacklistResourceMapper.MapToResource(blacklist, _formatCalculator)); } + private List GetMovieBlacklist() + { + var queryMovieId = Request.Query.MovieId; + + if (!queryMovieId.HasValue) + { + throw new BadRequestException("movieId is missing"); + } + + int movieId = Convert.ToInt32(queryMovieId.Value); + + return _blacklistService.GetByMovieId(movieId).Select(h => BlacklistResourceMapper.MapToResource(h, _formatCalculator)).ToList(); + } + private void DeleteBlacklist(int id) { _blacklistService.Delete(id);