mirror of
https://github.com/Radarr/Radarr.git
synced 2024-08-16 23:39:44 +02:00
New: Calendar filtering by tags
Closes #8502 (cherry picked from commit 62b948b24c4b9c572db225cb19985444d3d80c0f)
This commit is contained in:
parent
a39cafe404
commit
3878196f39
@ -1,4 +1,5 @@
|
|||||||
import InteractiveImportAppState from 'App/State/InteractiveImportAppState';
|
import InteractiveImportAppState from 'App/State/InteractiveImportAppState';
|
||||||
|
import CalendarAppState from './CalendarAppState';
|
||||||
import CommandAppState from './CommandAppState';
|
import CommandAppState from './CommandAppState';
|
||||||
import MovieCollectionAppState from './MovieCollectionAppState';
|
import MovieCollectionAppState from './MovieCollectionAppState';
|
||||||
import MovieFilesAppState from './MovieFilesAppState';
|
import MovieFilesAppState from './MovieFilesAppState';
|
||||||
@ -43,6 +44,7 @@ export interface CustomFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface AppState {
|
interface AppState {
|
||||||
|
calendar: CalendarAppState;
|
||||||
commands: CommandAppState;
|
commands: CommandAppState;
|
||||||
interactiveImport: InteractiveImportAppState;
|
interactiveImport: InteractiveImportAppState;
|
||||||
movieCollections: MovieCollectionAppState;
|
movieCollections: MovieCollectionAppState;
|
||||||
|
9
frontend/src/App/State/CalendarAppState.ts
Normal file
9
frontend/src/App/State/CalendarAppState.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import AppSectionState from 'App/State/AppSectionState';
|
||||||
|
import Movie from 'Movie/Movie';
|
||||||
|
import { FilterBuilderProp } from './AppState';
|
||||||
|
|
||||||
|
interface CalendarAppState extends AppSectionState<Movie> {
|
||||||
|
filterBuilderProps: FilterBuilderProp<Movie>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CalendarAppState;
|
56
frontend/src/Calendar/CalendarFilterModal.tsx
Normal file
56
frontend/src/Calendar/CalendarFilterModal.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import AppState from 'App/State/AppState';
|
||||||
|
import FilterModal from 'Components/Filter/FilterModal';
|
||||||
|
import { setCalendarFilter } from 'Store/Actions/calendarActions';
|
||||||
|
|
||||||
|
function createCalendarSelector() {
|
||||||
|
return createSelector(
|
||||||
|
(state: AppState) => state.calendar.items,
|
||||||
|
(calendar) => {
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFilterBuilderPropsSelector() {
|
||||||
|
return createSelector(
|
||||||
|
(state: AppState) => state.calendar.filterBuilderProps,
|
||||||
|
(filterBuilderProps) => {
|
||||||
|
return filterBuilderProps;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SeriesIndexFilterModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CalendarFilterModal(
|
||||||
|
props: SeriesIndexFilterModalProps
|
||||||
|
) {
|
||||||
|
const sectionItems = useSelector(createCalendarSelector());
|
||||||
|
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
|
||||||
|
const customFilterType = 'calendar';
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const dispatchSetFilter = useCallback(
|
||||||
|
(payload: unknown) => {
|
||||||
|
dispatch(setCalendarFilter(payload));
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FilterModal
|
||||||
|
// TODO: Don't spread all the props
|
||||||
|
{...props}
|
||||||
|
sectionItems={sectionItems}
|
||||||
|
filterBuilderProps={filterBuilderProps}
|
||||||
|
customFilterType={customFilterType}
|
||||||
|
dispatchSetFilter={dispatchSetFilter}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -14,6 +14,7 @@ import NoMovie from 'Movie/NoMovie';
|
|||||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import CalendarConnector from './CalendarConnector';
|
import CalendarConnector from './CalendarConnector';
|
||||||
|
import CalendarFilterModal from './CalendarFilterModal';
|
||||||
import CalendarLinkModal from './iCal/CalendarLinkModal';
|
import CalendarLinkModal from './iCal/CalendarLinkModal';
|
||||||
import LegendConnector from './Legend/LegendConnector';
|
import LegendConnector from './Legend/LegendConnector';
|
||||||
import CalendarOptionsModal from './Options/CalendarOptionsModal';
|
import CalendarOptionsModal from './Options/CalendarOptionsModal';
|
||||||
@ -83,6 +84,7 @@ class CalendarPage extends Component {
|
|||||||
movieIsFetching,
|
movieIsFetching,
|
||||||
movieIsPopulated,
|
movieIsPopulated,
|
||||||
missingMovieIds,
|
missingMovieIds,
|
||||||
|
customFilters,
|
||||||
isRssSyncExecuting,
|
isRssSyncExecuting,
|
||||||
isSearchingForMissing,
|
isSearchingForMissing,
|
||||||
useCurrentPage,
|
useCurrentPage,
|
||||||
@ -137,7 +139,8 @@ class CalendarPage extends Component {
|
|||||||
isDisabled={!hasMovie}
|
isDisabled={!hasMovie}
|
||||||
selectedFilterKey={selectedFilterKey}
|
selectedFilterKey={selectedFilterKey}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
customFilters={[]}
|
customFilters={customFilters}
|
||||||
|
filterModalConnectorComponent={CalendarFilterModal}
|
||||||
onFilterSelect={onFilterSelect}
|
onFilterSelect={onFilterSelect}
|
||||||
/>
|
/>
|
||||||
</PageToolbarSection>
|
</PageToolbarSection>
|
||||||
@ -208,6 +211,7 @@ CalendarPage.propTypes = {
|
|||||||
movieIsFetching: PropTypes.bool.isRequired,
|
movieIsFetching: PropTypes.bool.isRequired,
|
||||||
movieIsPopulated: PropTypes.bool.isRequired,
|
movieIsPopulated: PropTypes.bool.isRequired,
|
||||||
missingMovieIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
missingMovieIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
|
customFilters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
isRssSyncExecuting: PropTypes.bool.isRequired,
|
isRssSyncExecuting: PropTypes.bool.isRequired,
|
||||||
isSearchingForMissing: PropTypes.bool.isRequired,
|
isSearchingForMissing: PropTypes.bool.isRequired,
|
||||||
useCurrentPage: PropTypes.bool.isRequired,
|
useCurrentPage: PropTypes.bool.isRequired,
|
||||||
|
@ -5,6 +5,7 @@ import * as commandNames from 'Commands/commandNames';
|
|||||||
import withCurrentPage from 'Components/withCurrentPage';
|
import withCurrentPage from 'Components/withCurrentPage';
|
||||||
import { searchMissing, setCalendarDaysCount, setCalendarFilter } from 'Store/Actions/calendarActions';
|
import { searchMissing, setCalendarDaysCount, setCalendarFilter } from 'Store/Actions/calendarActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
|
import { createCustomFiltersSelector } from 'Store/Selectors/createClientSideCollectionSelector';
|
||||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||||
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
||||||
import createMovieCountSelector from 'Store/Selectors/createMovieCountSelector';
|
import createMovieCountSelector from 'Store/Selectors/createMovieCountSelector';
|
||||||
@ -59,6 +60,7 @@ function createMapStateToProps() {
|
|||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.calendar.selectedFilterKey,
|
(state) => state.calendar.selectedFilterKey,
|
||||||
(state) => state.calendar.filters,
|
(state) => state.calendar.filters,
|
||||||
|
createCustomFiltersSelector('calendar'),
|
||||||
createMovieCountSelector(),
|
createMovieCountSelector(),
|
||||||
createUISettingsSelector(),
|
createUISettingsSelector(),
|
||||||
createMissingMovieIdsSelector(),
|
createMissingMovieIdsSelector(),
|
||||||
@ -67,6 +69,7 @@ function createMapStateToProps() {
|
|||||||
(
|
(
|
||||||
selectedFilterKey,
|
selectedFilterKey,
|
||||||
filters,
|
filters,
|
||||||
|
customFilters,
|
||||||
movieCount,
|
movieCount,
|
||||||
uiSettings,
|
uiSettings,
|
||||||
missingMovieIds,
|
missingMovieIds,
|
||||||
@ -76,6 +79,7 @@ function createMapStateToProps() {
|
|||||||
return {
|
return {
|
||||||
selectedFilterKey,
|
selectedFilterKey,
|
||||||
filters,
|
filters,
|
||||||
|
customFilters,
|
||||||
colorImpairedMode: uiSettings.enableColorImpairedMode,
|
colorImpairedMode: uiSettings.enableColorImpairedMode,
|
||||||
hasMovie: !!movieCount.count,
|
hasMovie: !!movieCount.count,
|
||||||
movieError: movieCount.error,
|
movieError: movieCount.error,
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import * as filterTypes from './filterTypes';
|
import * as filterTypes from './filterTypes';
|
||||||
|
|
||||||
export const ARRAY = 'array';
|
export const ARRAY = 'array';
|
||||||
|
export const CONTAINS = 'contains';
|
||||||
export const DATE = 'date';
|
export const DATE = 'date';
|
||||||
|
export const EQUAL = 'equal';
|
||||||
export const EXACT = 'exact';
|
export const EXACT = 'exact';
|
||||||
export const NUMBER = 'number';
|
export const NUMBER = 'number';
|
||||||
export const STRING = 'string';
|
export const STRING = 'string';
|
||||||
|
|
||||||
export const all = [
|
export const all = [
|
||||||
ARRAY,
|
ARRAY,
|
||||||
|
CONTAINS,
|
||||||
DATE,
|
DATE,
|
||||||
|
EQUAL,
|
||||||
EXACT,
|
EXACT,
|
||||||
NUMBER,
|
NUMBER,
|
||||||
STRING
|
STRING
|
||||||
@ -20,6 +24,10 @@ export const possibleFilterTypes = {
|
|||||||
{ key: filterTypes.NOT_CONTAINS, value: 'does not contain' }
|
{ key: filterTypes.NOT_CONTAINS, value: 'does not contain' }
|
||||||
],
|
],
|
||||||
|
|
||||||
|
[CONTAINS]: [
|
||||||
|
{ key: filterTypes.CONTAINS, value: 'contains' }
|
||||||
|
],
|
||||||
|
|
||||||
[DATE]: [
|
[DATE]: [
|
||||||
{ key: filterTypes.LESS_THAN, value: 'is before' },
|
{ key: filterTypes.LESS_THAN, value: 'is before' },
|
||||||
{ key: filterTypes.GREATER_THAN, value: 'is after' },
|
{ key: filterTypes.GREATER_THAN, value: 'is after' },
|
||||||
@ -29,6 +37,10 @@ export const possibleFilterTypes = {
|
|||||||
{ key: filterTypes.NOT_IN_NEXT, value: 'not in the next' }
|
{ key: filterTypes.NOT_IN_NEXT, value: 'not in the next' }
|
||||||
],
|
],
|
||||||
|
|
||||||
|
[EQUAL]: [
|
||||||
|
{ key: filterTypes.EQUAL, value: 'is' }
|
||||||
|
],
|
||||||
|
|
||||||
[EXACT]: [
|
[EXACT]: [
|
||||||
{ key: filterTypes.EQUAL, value: 'is' },
|
{ key: filterTypes.EQUAL, value: 'is' },
|
||||||
{ key: filterTypes.NOT_EQUAL, value: 'is not' }
|
{ key: filterTypes.NOT_EQUAL, value: 'is not' }
|
||||||
|
@ -4,9 +4,10 @@ import { createAction } from 'redux-actions';
|
|||||||
import { batchActions } from 'redux-batched-actions';
|
import { batchActions } from 'redux-batched-actions';
|
||||||
import * as calendarViews from 'Calendar/calendarViews';
|
import * as calendarViews from 'Calendar/calendarViews';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import { filterTypes } from 'Helpers/Props';
|
import { filterBuilderTypes, filterBuilderValueTypes, filterTypes } from 'Helpers/Props';
|
||||||
import { createThunk, handleThunks } from 'Store/thunks';
|
import { createThunk, handleThunks } from 'Store/thunks';
|
||||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||||
|
import findSelectedFilters from 'Utilities/Filter/findSelectedFilters';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import { set, update } from './baseActions';
|
import { set, update } from './baseActions';
|
||||||
import { executeCommandHelper } from './commandActions';
|
import { executeCommandHelper } from './commandActions';
|
||||||
@ -47,14 +48,16 @@ export const defaultState = {
|
|||||||
|
|
||||||
selectedFilterKey: 'monitored',
|
selectedFilterKey: 'monitored',
|
||||||
|
|
||||||
|
customFilters: [],
|
||||||
|
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'all',
|
key: 'all',
|
||||||
label: () => translate('All'),
|
label: () => translate('All'),
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'monitored',
|
key: 'unmonitored',
|
||||||
value: false,
|
value: [true],
|
||||||
type: filterTypes.EQUAL
|
type: filterTypes.EQUAL
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -64,20 +67,35 @@ export const defaultState = {
|
|||||||
label: () => translate('MonitoredOnly'),
|
label: () => translate('MonitoredOnly'),
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'monitored',
|
key: 'unmonitored',
|
||||||
value: true,
|
value: [false],
|
||||||
type: filterTypes.EQUAL
|
type: filterTypes.EQUAL
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
filterBuilderProps: [
|
||||||
|
{
|
||||||
|
name: 'unmonitored',
|
||||||
|
label: () => translate('IncludeUnmonitored'),
|
||||||
|
type: filterBuilderTypes.EQUAL,
|
||||||
|
valueType: filterBuilderValueTypes.BOOL
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'tags',
|
||||||
|
label: () => translate('Tags'),
|
||||||
|
type: filterBuilderTypes.CONTAINS,
|
||||||
|
valueType: filterBuilderValueTypes.TAG
|
||||||
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const persistState = [
|
export const persistState = [
|
||||||
'calendar.view',
|
'calendar.view',
|
||||||
'calendar.selectedFilterKey',
|
'calendar.selectedFilterKey',
|
||||||
'calendar.options'
|
'calendar.options',
|
||||||
|
'movieIndex.customFilters'
|
||||||
];
|
];
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -189,6 +207,10 @@ function isRangePopulated(start, end, state) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCustomFilters(state, type) {
|
||||||
|
return state.customFilters.items.filter((customFilter) => customFilter.type === type);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Action Creators
|
// Action Creators
|
||||||
|
|
||||||
@ -210,7 +232,8 @@ export const actionHandlers = handleThunks({
|
|||||||
[FETCH_CALENDAR]: function(getState, payload, dispatch) {
|
[FETCH_CALENDAR]: function(getState, payload, dispatch) {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const calendar = state.calendar;
|
const calendar = state.calendar;
|
||||||
const unmonitored = calendar.selectedFilterKey === 'all';
|
const customFilters = getCustomFilters(state, section);
|
||||||
|
const selectedFilters = findSelectedFilters(calendar.selectedFilterKey, calendar.filters, customFilters);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
time = calendar.time,
|
time = calendar.time,
|
||||||
@ -237,13 +260,26 @@ export const actionHandlers = handleThunks({
|
|||||||
|
|
||||||
dispatch(set(attrs));
|
dispatch(set(attrs));
|
||||||
|
|
||||||
|
const requestParams = {
|
||||||
|
start,
|
||||||
|
end
|
||||||
|
};
|
||||||
|
|
||||||
|
selectedFilters.forEach((selectedFilter) => {
|
||||||
|
if (selectedFilter.key === 'unmonitored') {
|
||||||
|
requestParams.unmonitored = selectedFilter.value.includes(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedFilter.key === 'tags') {
|
||||||
|
requestParams.tags = selectedFilter.value.join(',');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
requestParams.unmonitored = requestParams.unmonitored ?? false;
|
||||||
|
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/calendar',
|
url: '/calendar',
|
||||||
data: {
|
data: requestParams
|
||||||
unmonitored,
|
|
||||||
start,
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}).request;
|
}).request;
|
||||||
|
|
||||||
promise.done((data) => {
|
promise.done((data) => {
|
||||||
|
@ -108,7 +108,7 @@ function sort(items, state) {
|
|||||||
return _.orderBy(items, clauses, orders);
|
return _.orderBy(items, clauses, orders);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCustomFiltersSelector(type, alternateType) {
|
export function createCustomFiltersSelector(type, alternateType) {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.customFilters.items,
|
(state) => state.customFilters.items,
|
||||||
(customFilters) => {
|
(customFilters) => {
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
const thunks = {};
|
|
||||||
|
|
||||||
function identity(payload) {
|
|
||||||
return payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createThunk(type, identityFunction = identity) {
|
|
||||||
return function(payload = {}) {
|
|
||||||
return function(dispatch, getState) {
|
|
||||||
const thunk = thunks[type];
|
|
||||||
|
|
||||||
if (thunk) {
|
|
||||||
return thunk(getState, identityFunction(payload), dispatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw Error(`Thunk handler has not been registered for ${type}`);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function handleThunks(handlers) {
|
|
||||||
const types = Object.keys(handlers);
|
|
||||||
|
|
||||||
types.forEach((type) => {
|
|
||||||
thunks[type] = handlers[type];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -2,11 +2,13 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
using NzbDrone.Core.Languages;
|
using NzbDrone.Core.Languages;
|
||||||
using NzbDrone.Core.Movies;
|
using NzbDrone.Core.Movies;
|
||||||
using NzbDrone.Core.Movies.Translations;
|
using NzbDrone.Core.Movies.Translations;
|
||||||
|
using NzbDrone.Core.Tags;
|
||||||
using NzbDrone.SignalR;
|
using NzbDrone.SignalR;
|
||||||
using Radarr.Api.V3.Movies;
|
using Radarr.Api.V3.Movies;
|
||||||
using Radarr.Http;
|
using Radarr.Http;
|
||||||
@ -20,18 +22,21 @@ public class CalendarController : RestControllerWithSignalR<MovieResource, Movie
|
|||||||
private readonly IMovieService _moviesService;
|
private readonly IMovieService _moviesService;
|
||||||
private readonly IMovieTranslationService _movieTranslationService;
|
private readonly IMovieTranslationService _movieTranslationService;
|
||||||
private readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
private readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
||||||
|
private readonly ITagService _tagService;
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
|
|
||||||
public CalendarController(IBroadcastSignalRMessage signalR,
|
public CalendarController(IBroadcastSignalRMessage signalR,
|
||||||
IMovieService moviesService,
|
IMovieService moviesService,
|
||||||
IMovieTranslationService movieTranslationService,
|
IMovieTranslationService movieTranslationService,
|
||||||
IUpgradableSpecification qualityUpgradableSpecification,
|
IUpgradableSpecification qualityUpgradableSpecification,
|
||||||
|
ITagService tagService,
|
||||||
IConfigService configService)
|
IConfigService configService)
|
||||||
: base(signalR)
|
: base(signalR)
|
||||||
{
|
{
|
||||||
_moviesService = moviesService;
|
_moviesService = moviesService;
|
||||||
_movieTranslationService = movieTranslationService;
|
_movieTranslationService = movieTranslationService;
|
||||||
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
|
_tagService = tagService;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,12 +47,36 @@ protected override MovieResource GetResourceById(int id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public List<MovieResource> GetCalendar(DateTime? start, DateTime? end, bool unmonitored = false)
|
[Produces("application/json")]
|
||||||
|
public List<MovieResource> GetCalendar(DateTime? start, DateTime? end, bool unmonitored = false, string tags = "")
|
||||||
{
|
{
|
||||||
var startUse = start ?? DateTime.Today;
|
var startUse = start ?? DateTime.Today;
|
||||||
var endUse = end ?? DateTime.Today.AddDays(2);
|
var endUse = end ?? DateTime.Today.AddDays(2);
|
||||||
|
var movies = _moviesService.GetMoviesBetweenDates(startUse, endUse, unmonitored);
|
||||||
|
var parsedTags = new List<int>();
|
||||||
|
var result = new List<Movie>();
|
||||||
|
|
||||||
var resources = _moviesService.GetMoviesBetweenDates(startUse, endUse, unmonitored).Select(MapToResource);
|
if (tags.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
parsedTags.AddRange(tags.Split(',').Select(_tagService.GetTag).Select(t => t.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var movie in movies)
|
||||||
|
{
|
||||||
|
if (movie == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedTags.Any() && parsedTags.None(movie.Tags.Contains))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Add(movie);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resources = result.Select(MapToResource);
|
||||||
|
|
||||||
return resources.OrderBy(e => e.InCinemas).ToList();
|
return resources.OrderBy(e => e.InCinemas).ToList();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user