diff --git a/NzbDrone.Api/History/HistoryModule.cs b/NzbDrone.Api/History/HistoryModule.cs index b4fefdfcf..e46f253ba 100644 --- a/NzbDrone.Api/History/HistoryModule.cs +++ b/NzbDrone.Api/History/HistoryModule.cs @@ -13,48 +13,27 @@ using NzbDrone.Core.Tv; namespace NzbDrone.Api.History { - public class HistoryModule : NzbDroneApiModule + public class HistoryModule : NzbDroneRestModule<HistoryResource> { private readonly IHistoryService _historyService; public HistoryModule(IHistoryService historyService) - : base("/history") { _historyService = historyService; - Get["/"] = x => GetHistory(); + GetResourcePaged = GetHistory; } - private Response GetHistory() + private PagingResource<HistoryResource> GetHistory(PagingResource<HistoryResource> pagingResource) { - //TODO: common page parsing logic should be done somewhere else - - int pageSize; - Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.PageSize), out pageSize); - if (pageSize == 0) pageSize = 20; - - int page; - Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.Page), out page); - if (page == 0) page = 1; - - var sortKey = PrimitiveExtensions.ToNullSafeString(Request.Query.SortKey); - if (String.IsNullOrEmpty(sortKey)) sortKey = "AirDate"; - - var sortDirection = PrimitiveExtensions.ToNullSafeString(Request.Query.SortDir) - .Equals("Asc", StringComparison.InvariantCultureIgnoreCase) - ? SortDirection.Ascending - : SortDirection.Descending; - var pagingSpec = new PagingSpec<Core.History.History> { - Page = page, - PageSize = pageSize, - SortKey = sortKey, - SortDirection = sortDirection + Page = pagingResource.Page, + PageSize = pagingResource.PageSize, + SortKey = pagingResource.SortKey, + SortDirection = pagingResource.SortDirection }; - var result = _historyService.Paged(pagingSpec); - - return Mapper.Map<PagingSpec<Core.History.History>, PagingResource<HistoryResource>>(result).AsResponse(); + return ApplyToPage(_historyService.Paged, pagingSpec); } } } \ No newline at end of file diff --git a/NzbDrone.Api/Missing/MissingModule.cs b/NzbDrone.Api/Missing/MissingModule.cs index a316601a8..22673c2ab 100644 --- a/NzbDrone.Api/Missing/MissingModule.cs +++ b/NzbDrone.Api/Missing/MissingModule.cs @@ -1,59 +1,29 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using AutoMapper; -using Nancy; -using NzbDrone.Api.Episodes; -using NzbDrone.Api.Extensions; -using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Tv; namespace NzbDrone.Api.Missing { - public class MissingModule : NzbDroneApiModule + public class MissingModule : NzbDroneRestModule<MissingResource> { private readonly IEpisodeService _episodeService; public MissingModule(IEpisodeService episodeService) - : base("/missing") { _episodeService = episodeService; - Get["/"] = x => GetMissingEpisodes(); + GetResourcePaged = GetMissingEpisodes; } - private Response GetMissingEpisodes() + private PagingResource<MissingResource> GetMissingEpisodes(PagingResource<MissingResource> pagingResource) { - bool includeSpecials; - Boolean.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.IncludeSpecials), out includeSpecials); - - int pageSize; - Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.PageSize), out pageSize); - if (pageSize == 0) pageSize = 20; - - int page; - Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.Page), out page); - if (page == 0) page = 1; - - var sortKey = PrimitiveExtensions.ToNullSafeString(Request.Query.SortKey); - if (String.IsNullOrEmpty(sortKey)) sortKey = "AirDate"; - - var sortDirection = PrimitiveExtensions.ToNullSafeString(Request.Query.SortDir) - .Equals("Asc", StringComparison.InvariantCultureIgnoreCase) - ? SortDirection.Ascending - : SortDirection.Descending; - var pagingSpec = new PagingSpec<Episode> - { - Page = page, - PageSize = pageSize, - SortKey = sortKey, - SortDirection = sortDirection - }; - - var result = _episodeService.EpisodesWithoutFiles(pagingSpec, includeSpecials); - - return Mapper.Map<PagingSpec<Episode>, PagingResource<EpisodeResource>>(result).AsResponse(); + { + Page = pagingResource.Page, + PageSize = pagingResource.PageSize, + SortKey = pagingResource.SortKey, + SortDirection = pagingResource.SortDirection + }; + + return ApplyToPage(_episodeService.EpisodesWithoutFiles, pagingSpec); } } } \ No newline at end of file diff --git a/NzbDrone.Api/Missing/MissingResource.cs b/NzbDrone.Api/Missing/MissingResource.cs new file mode 100644 index 000000000..11bd7704b --- /dev/null +++ b/NzbDrone.Api/Missing/MissingResource.cs @@ -0,0 +1,34 @@ +using System; +using NzbDrone.Api.REST; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Model; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Api.Missing +{ + public class MissingResource : RestResource + { + public Int32 Id { get; set; } + public Int32 SeriesId { get; set; } + public Int32 EpisodeFileId { get; set; } + public Int32 SeasonNumber { get; set; } + public Int32 EpisodeNumber { get; set; } + public String Title { get; set; } + public DateTime? AirDate { get; set; } + public EpisodeStatuses Status { get; set; } + public String Overview { get; set; } + public EpisodeFile EpisodeFile { get; set; } + + public Boolean HasFile { get; set; } + public Boolean Ignored { get; set; } + public Int32 SceneEpisodeNumber { get; set; } + public Int32 SceneSeasonNumber { get; set; } + public Int32 TvDbEpisodeId { get; set; } + public Int32? AbsoluteEpisodeNumber { get; set; } + public DateTime? EndTime { get; set; } + public DateTime? GrabDate { get; set; } + public PostDownloadStatusType PostDownloadStatus { get; set; } + public Core.Tv.Series Series { get; set; } + public String SeriesTitle { get; set; } + } +} diff --git a/NzbDrone.Api/NzbDrone.Api.csproj b/NzbDrone.Api/NzbDrone.Api.csproj index 7694cf32b..1e08e4fc1 100644 --- a/NzbDrone.Api/NzbDrone.Api.csproj +++ b/NzbDrone.Api/NzbDrone.Api.csproj @@ -109,6 +109,7 @@ <Compile Include="Mapping\MappingValidation.cs" /> <Compile Include="Mapping\ResourceMappingException.cs" /> <Compile Include="Mapping\ValueInjectorExtensions.cs" /> + <Compile Include="Missing\MissingResource.cs" /> <Compile Include="Missing\MissingModule.cs" /> <Compile Include="NzbDroneRestModule.cs" /> <Compile Include="PagingResource.cs" /> diff --git a/NzbDrone.Api/NzbDroneRestModule.cs b/NzbDrone.Api/NzbDroneRestModule.cs index 0b026eea3..87507b234 100644 --- a/NzbDrone.Api/NzbDroneRestModule.cs +++ b/NzbDrone.Api/NzbDroneRestModule.cs @@ -48,5 +48,19 @@ namespace NzbDrone.Api return model.InjectTo<TResource>(); } + protected PagingResource<TResource> ApplyToPage<TModel>(Func<PagingSpec<TModel>, PagingSpec<TModel>> function, PagingSpec<TModel> pagingSpec) where TModel : ModelBase, new() + { + pagingSpec = function(pagingSpec); + + return new PagingResource<TResource> + { + Page = pagingSpec.Page, + PageSize = pagingSpec.PageSize, + SortDirection = pagingSpec.SortDirection, + SortKey = pagingSpec.SortKey, + TotalRecords = pagingSpec.TotalRecords, + Records = pagingSpec.Records.InjectTo<List<TResource>>() + }; + } } } \ No newline at end of file diff --git a/NzbDrone.Api/PagingResource.cs b/NzbDrone.Api/PagingResource.cs index 389552c5b..7452c9bff 100644 --- a/NzbDrone.Api/PagingResource.cs +++ b/NzbDrone.Api/PagingResource.cs @@ -2,13 +2,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using NzbDrone.Core.Datastore; namespace NzbDrone.Api { public class PagingResource<TModel> { public int Page { get; set; } + public int PageSize { get; set; } public string SortKey { get; set; } + public SortDirection SortDirection { get; set; } public int TotalRecords { get; set; } public List<TModel> Records { get; set; } } diff --git a/NzbDrone.Api/REST/RestModule.cs b/NzbDrone.Api/REST/RestModule.cs index 79e0f4b8c..9e57625ab 100644 --- a/NzbDrone.Api/REST/RestModule.cs +++ b/NzbDrone.Api/REST/RestModule.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; +using AutoMapper; using FluentValidation; using Nancy; using NzbDrone.Api.Extensions; using System.Linq; +using NzbDrone.Core.Datastore; namespace NzbDrone.Api.REST { @@ -16,6 +18,7 @@ namespace NzbDrone.Api.REST private Action<int> _deleteResource; private Func<int, TResource> _getResourceById; private Func<List<TResource>> _getResourceAll; + private Func<PagingResource<TResource>, PagingResource<TResource>> _getResourcePaged; private Func<TResource> _getResourceSingle; private Func<TResource, TResource> _createResource; private Func<TResource, TResource> _updateResource; @@ -24,7 +27,6 @@ namespace NzbDrone.Api.REST protected ResourceValidator<TResource> PutValidator { get; private set; } protected ResourceValidator<TResource> SharedValidator { get; private set; } - protected void ValidateId(int id) { if (id <= 0) @@ -33,7 +35,6 @@ namespace NzbDrone.Api.REST } } - protected RestModule(string modulePath) : base(modulePath) { @@ -88,6 +89,21 @@ namespace NzbDrone.Api.REST } } + protected Func<PagingResource<TResource>, PagingResource<TResource>> GetResourcePaged + { + private get { return _getResourcePaged; } + set + { + _getResourcePaged = value; + + Get[ROOT_ROUTE] = options => + { + var resource = GetResourcePaged(ReadPagingResourceFromRequest()); + return resource.AsResponse(); + }; + } + } + protected Func<TResource> GetResourceSingle { private get { return _getResourceSingle; } @@ -132,7 +148,6 @@ namespace NzbDrone.Api.REST } } - private TResource ReadFromRequest() { //TODO: handle when request is null @@ -140,7 +155,6 @@ namespace NzbDrone.Api.REST var errors = SharedValidator.Validate(resource).Errors.ToList(); - if (Request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase)) { errors.AddRange(PostValidator.Validate(resource).Errors); @@ -157,5 +171,34 @@ namespace NzbDrone.Api.REST return resource; } + + private PagingResource<TResource> ReadPagingResourceFromRequest() + { + int pageSize; + Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.PageSize), out pageSize); + if (pageSize == 0) pageSize = 10; + + int page; + Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.Page), out page); + if (page == 0) page = 1; + + var sortKey = PrimitiveExtensions.ToNullSafeString(Request.Query.SortKey); + if (String.IsNullOrEmpty(sortKey)) sortKey = "AirDate"; + + var sortDirection = PrimitiveExtensions.ToNullSafeString(Request.Query.SortDir) + .Equals("Asc", StringComparison.InvariantCultureIgnoreCase) + ? SortDirection.Ascending + : SortDirection.Descending; + + var pagingResource = new PagingResource<TResource> + { + PageSize = pageSize, + Page = page, + SortKey = sortKey, + SortDirection = sortDirection + }; + + return pagingResource; + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Tv/EpisodeService.cs b/NzbDrone.Core/Tv/EpisodeService.cs index 12d68ab8a..28e19f7c9 100644 --- a/NzbDrone.Core/Tv/EpisodeService.cs +++ b/NzbDrone.Core/Tv/EpisodeService.cs @@ -21,7 +21,7 @@ namespace NzbDrone.Core.Tv Episode GetEpisode(int seriesId, DateTime date); List<Episode> GetEpisodeBySeries(int seriesId); List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber); - PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials); + PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec); List<Episode> GetEpisodesByFileId(int episodeFileId); List<Episode> EpisodesWithFiles(); void RefreshEpisodeInfo(Series series); @@ -93,9 +93,9 @@ namespace NzbDrone.Core.Tv return _episodeRepository.GetEpisodes(seriesId, seasonNumber); } - public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials) + public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec) { - var episodeResult = _episodeRepository.EpisodesWithoutFiles(pagingSpec, includeSpecials); + var episodeResult = _episodeRepository.EpisodesWithoutFiles(pagingSpec, false); return episodeResult; } diff --git a/NzbDrone.ncrunchsolution b/NzbDrone.ncrunchsolution index 444b34b1d..6cb47a29a 100644 --- a/NzbDrone.ncrunchsolution +++ b/NzbDrone.ncrunchsolution @@ -2,7 +2,6 @@ <FileVersion>1</FileVersion> <AutoEnableOnStartup>False</AutoEnableOnStartup> <AllowParallelTestExecution>true</AllowParallelTestExecution> - <AllowTestsToRunInParallelWithThemselves>true</AllowTestsToRunInParallelWithThemselves> <FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit> <FrameworkUtilisationTypeForGallio>Disabled</FrameworkUtilisationTypeForGallio> <FrameworkUtilisationTypeForMSpec>Disabled</FrameworkUtilisationTypeForMSpec> diff --git a/UI/AddSeries/New/AddNewSeriesView.js b/UI/AddSeries/New/AddNewSeriesView.js index 95c0b6d09..e1f973fdf 100644 --- a/UI/AddSeries/New/AddNewSeriesView.js +++ b/UI/AddSeries/New/AddNewSeriesView.js @@ -16,8 +16,6 @@ define(['app', 'AddSeries/RootFolders/RootFolderCollection', 'AddSeries/New/Sear initialize: function () { this.collection = new NzbDrone.AddSeries.Collection(); - - model.id = undefined; NzbDrone.AddSeries.New.AddNewSeriesContext = this; NzbDrone.vent.on(NzbDrone.Events.SeriesAdded, function (options) {