Added more magic to fancy. it now automatically figures our response for PUT and POST based on request ID.

file name sample uses HTTP GET instead of post
This commit is contained in:
kay.one 2013-08-25 22:14:55 -07:00
parent 438e3199de
commit 4188946395
20 changed files with 135 additions and 198 deletions

View File

@ -1,5 +1,6 @@
using System;
using System.Linq;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Common.Composition;
using NzbDrone.Common.Messaging;
@ -16,10 +17,11 @@ namespace NzbDrone.Api.Commands
_messageAggregator = messageAggregator;
_container = container;
CreateResource = RunCommand;
Post["/"] = x => RunCommand(ReadResourceFromRequest());
}
private CommandResource RunCommand(CommandResource resource)
private Response RunCommand(CommandResource resource)
{
var commandType =
_container.GetImplementations(typeof(ICommand))
@ -29,7 +31,7 @@ namespace NzbDrone.Api.Commands
dynamic command = Request.Body.FromJson(commandType);
_messageAggregator.PublishCommand(command);
return resource;
return resource.AsResponse();
}
}
}

View File

@ -1,33 +1,93 @@
using FluentValidation;
using System.Collections.Generic;
using FluentValidation;
using Nancy.Responses;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using Nancy.ModelBinding;
using NzbDrone.Api.Mapping;
using NzbDrone.Api.Extensions;
namespace NzbDrone.Api.Config
{
public class NamingModule : NzbDroneRestModule<NamingConfigResource>
{
private readonly INamingConfigService _namingConfigService;
private readonly IBuildFileNames _buildFileNames;
public NamingModule(INamingConfigService namingConfigService)
public NamingModule(INamingConfigService namingConfigService, IBuildFileNames buildFileNames)
: base("config/naming")
{
_namingConfigService = namingConfigService;
_buildFileNames = buildFileNames;
GetResourceSingle = GetNamingConfig;
UpdateResource = UpdateNamingConfig;
Get["/samples"] = x => GetExamples(this.Bind<NamingConfigResource>());
SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 3);
SharedValidator.RuleFor(c => c.NumberStyle).InclusiveBetween(0, 3);
SharedValidator.RuleFor(c => c.Separator).Matches(@"\s|\s\-\s|\.");
}
private NamingConfigResource UpdateNamingConfig(NamingConfigResource resource)
private void UpdateNamingConfig(NamingConfigResource resource)
{
return ToResource<NamingConfig>(_namingConfigService.Save, resource);
GetNewId<NamingConfig>(_namingConfigService.Save, resource);
}
private NamingConfigResource GetNamingConfig()
{
return ToResource(_namingConfigService.GetConfig);
return _namingConfigService.GetConfig().InjectTo<NamingConfigResource>();
}
private JsonResponse<NamingSampleResource> GetExamples(NamingConfigResource config)
{
var nameSpec = config.InjectTo<NamingConfig>();
var series = new Core.Tv.Series
{
SeriesType = SeriesTypes.Standard,
Title = "Series Title"
};
var episode1 = new Episode
{
SeasonNumber = 1,
EpisodeNumber = 1,
Title = "Episode Title (1)"
};
var episode2 = new Episode
{
SeasonNumber = 1,
EpisodeNumber = 2,
Title = "Episode Title (2)"
};
var episodeFile = new EpisodeFile
{
Quality = new QualityModel(Quality.HDTV720p),
Path = @"C:\Test\Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv"
};
var sampleResource = new NamingSampleResource();
sampleResource.SingleEpisodeExample = _buildFileNames.BuildFilename(new List<Episode> { episode1 },
series,
episodeFile,
nameSpec);
episodeFile.Path = @"C:\Test\Series.Title.S01E01-E02.720p.HDTV.x264-EVOLVE.mkv";
sampleResource.MultiEpisodeExample = _buildFileNames.BuildFilename(new List<Episode> { episode1, episode2 },
series,
episodeFile,
nameSpec);
return sampleResource.AsResponse();
}
}
}

View File

@ -1,8 +1,6 @@
using NzbDrone.Api.Config;
namespace NzbDrone.Api.Naming
namespace NzbDrone.Api.Config
{
public class NamingResource : NamingConfigResource
public class NamingSampleResource
{
public string SingleEpisodeExample { get; set; }
public string MultiEpisodeExample { get; set; }

View File

@ -1,10 +1,7 @@
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
using NzbDrone.Api.Extensions;
using System.Linq;
using Omu.ValueInjecter;
using NzbDrone.Api.Mapping;
namespace NzbDrone.Api.EpisodeFiles
{
@ -23,7 +20,7 @@ namespace NzbDrone.Api.EpisodeFiles
private EpisodeFileResource GetEpisodeFile(int id)
{
return ToResource(() => _mediaFileService.Get(id));
return _mediaFileService.Get(id).InjectTo<EpisodeFileResource>();
}
private List<EpisodeFileResource> GetEpisodeFiles()
@ -38,15 +35,11 @@ namespace NzbDrone.Api.EpisodeFiles
return ToListResource(() => _mediaFileService.GetFilesBySeries(seriesId.Value));
}
private EpisodeFileResource SetQuality(EpisodeFileResource episodeFileResource)
private void SetQuality(EpisodeFileResource episodeFileResource)
{
var episodeFile = _mediaFileService.Get(episodeFileResource.Id);
episodeFile.Quality = episodeFileResource.Quality;
_mediaFileService.Update(episodeFile);
episodeFileResource.InjectFrom(episodeFile);
return episodeFileResource;
}
}
}

View File

@ -1,9 +1,6 @@
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
using NzbDrone.Api.Extensions;
using System.Linq;
namespace NzbDrone.Api.Episodes
{
@ -32,11 +29,9 @@ namespace NzbDrone.Api.Episodes
return ToListResource(() => _episodeService.GetEpisodeBySeries(seriesId.Value));
}
private EpisodeResource SetMonitored(EpisodeResource episodeResource)
private void SetMonitored(EpisodeResource episodeResource)
{
_episodeService.SetEpisodeMonitored(episodeResource.Id, episodeResource.Monitored);
return episodeResource;
}
}
}

View File

@ -31,7 +31,7 @@ namespace NzbDrone.Api.Frontend
path.StartsWith("/api", StringComparison.CurrentCultureIgnoreCase) ||
path.StartsWith("/signalr", StringComparison.CurrentCultureIgnoreCase))
{
return null;
return new NotFoundResponse();
}
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
@ -44,7 +44,7 @@ namespace NzbDrone.Api.Frontend
_logger.Warn("Couldn't find handler for {0}", path);
return null;
return new NotFoundResponse();
}
}
}

View File

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Api.Mapping;
using NzbDrone.Api.REST;
using NzbDrone.Core.Indexers;
using Omu.ValueInjecter;
@ -47,18 +46,14 @@ namespace NzbDrone.Api.Indexers
return result;
}
private IndexerResource CreateIndexer(IndexerResource indexerResource)
private int CreateIndexer(IndexerResource indexerResource)
{
var indexer = GetIndexer(indexerResource);
indexer = _indexerService.Create(indexer);
var response = indexer.InjectTo<IndexerResource>();
response.Fields = SchemaBuilder.GenerateSchema(indexer.Settings);
return response;
return indexer.Id;
}
private IndexerResource UpdateIndexer(IndexerResource indexerResource)
private void UpdateIndexer(IndexerResource indexerResource)
{
var indexer = _indexerService.Get(indexerResource.Id);
indexer.InjectFrom(indexerResource);
@ -66,12 +61,7 @@ namespace NzbDrone.Api.Indexers
ValidateIndexer(indexer);
indexer = _indexerService.Update(indexer);
var response = indexer.InjectTo<IndexerResource>();
response.Fields = SchemaBuilder.GenerateSchema(indexer.Settings);
return response;
_indexerService.Update(indexer);
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Mapping;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
@ -8,6 +9,8 @@ using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using Omu.ValueInjecter;
using System.Linq;
using Nancy.ModelBinding;
using NzbDrone.Api.Extensions;
namespace NzbDrone.Api.Indexers
{
@ -31,17 +34,17 @@ namespace NzbDrone.Api.Indexers
_downloadService = downloadService;
_parsingService = parsingService;
GetResourceAll = GetReleases;
CreateResource = DownloadRelease;
Post["/"] = x=> DownloadRelease(this.Bind<ReleaseResource>());
}
private ReleaseResource DownloadRelease(ReleaseResource release)
private Response DownloadRelease(ReleaseResource release)
{
var remoteEpisode = _parsingService.Map(release.InjectTo<ParsedEpisodeInfo>(), 0);
remoteEpisode.Report = release.InjectTo<ReportInfo>();
_downloadService.DownloadReport(remoteEpisode);
return release;
return release.AsResponse();
}
private List<ReleaseResource> GetReleases()

View File

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using NzbDrone.Api.Commands;
using NzbDrone.Api.Extensions;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
using Omu.ValueInjecter;
namespace NzbDrone.Api.Naming
{
public class NamingModule : NzbDroneRestModule<NamingResource>
{
private readonly IBuildFileNames _buildFileNames;
public NamingModule(IBuildFileNames buildFileNames)
:base("naming")
{
_buildFileNames = buildFileNames;
CreateResource = GetExamples;
}
private NamingResource GetExamples(NamingResource resource)
{
var nameSpec = new NamingConfig();
nameSpec.InjectFrom(resource);
var series = new Core.Tv.Series
{
SeriesType = SeriesTypes.Standard,
Title = "Series Title"
};
var episode1 = new Episode
{
SeasonNumber = 1,
EpisodeNumber = 1,
Title = "Episode Title (1)"
};
var episode2 = new Episode
{
SeasonNumber = 1,
EpisodeNumber = 2,
Title = "Episode Title (2)"
};
var episodeFile = new EpisodeFile
{
Quality = new QualityModel(Quality.HDTV720p),
Path = @"C:\Test\Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv"
};
resource.SingleEpisodeExample = _buildFileNames.BuildFilename(new List<Episode> { episode1 },
series,
episodeFile,
nameSpec);
episodeFile.Path = @"C:\Test\Series.Title.S01E01-E02.720p.HDTV.x264-EVOLVE.mkv";
resource.MultiEpisodeExample = _buildFileNames.BuildFilename(new List<Episode> { episode1, episode2 },
series,
episodeFile,
nameSpec);
return resource;
}
}
}

View File

@ -42,29 +42,17 @@ namespace NzbDrone.Api.Notifications
return result;
}
private NotificationResource Create(NotificationResource notificationResource)
private int Create(NotificationResource notificationResource)
{
var notification = GetNotification(notificationResource);
notification = _notificationService.Create(notification);
notificationResource.Id = notification.Id;
var response = notification.InjectTo<NotificationResource>();
response.Fields = SchemaBuilder.GenerateSchema(notification.Settings);
return response;
return _notificationService.Create(notification).Id;
}
private NotificationResource Update(NotificationResource notificationResource)
private void Update(NotificationResource notificationResource)
{
var notification = GetNotification(notificationResource);
notification.Id = notificationResource.Id;
notification = _notificationService.Update(notification);
var response = notification.InjectTo<NotificationResource>();
response.Fields = SchemaBuilder.GenerateSchema(notification.Settings);
return response;
_notificationService.Update(notification);
}
private void DeleteNotification(int id)

View File

@ -122,8 +122,7 @@
<Compile Include="Mapping\ResourceMappingException.cs" />
<Compile Include="Mapping\ValueInjectorExtensions.cs" />
<Compile Include="Missing\MissingModule.cs" />
<Compile Include="Naming\NamingResource.cs" />
<Compile Include="Naming\NamingModule.cs" />
<Compile Include="Config\NamingSampleResource.cs" />
<Compile Include="Notifications\NotificationSchemaModule.cs" />
<Compile Include="Notifications\NotificationModule.cs" />
<Compile Include="Notifications\NotificationResource.cs" />

View File

@ -22,11 +22,11 @@ namespace NzbDrone.Api
}
protected TResource ToResource<TModel>(Func<TModel, TModel> function, TResource resource) where TModel : ModelBase, new()
protected int GetNewId<TModel>(Func<TModel, TModel> function, TResource resource) where TModel : ModelBase, new()
{
var model = resource.InjectTo<TModel>();
function(model);
return model.InjectTo<TResource>();
return model.Id;
}
protected List<TResource> ToListResource<TModel>(Func<IEnumerable<TModel>> function) where TModel : ModelBase, new()
@ -35,17 +35,6 @@ namespace NzbDrone.Api
return modelList.InjectTo<List<TResource>>();
}
protected TResource ToResource<TModel>(Func<TModel> function) where TModel : ModelBase, new()
{
var modelList = function();
return modelList.InjectTo<TResource>();
}
protected TResource ToResource<TModel>(Func<int, TModel> action, int id) where TModel : ModelBase, new()
{
var model = action(id);
return model.InjectTo<TResource>();
}
protected PagingResource<TResource> ApplyToPage<TModel>(Func<PagingSpec<TModel>, PagingSpec<TModel>> function, PagingSpec<TModel> pagingSpec) where TModel : ModelBase, new()
{

View File

@ -30,11 +30,11 @@ namespace NzbDrone.Api.Qualities
DeleteResource = DeleteProfile;
}
private QualityProfileResource Create(QualityProfileResource resource)
private int Create(QualityProfileResource resource)
{
var model = resource.InjectTo<QualityProfile>();
model = _qualityProfileService.Add(model);
return GetById(model.Id);
return model.Id;
}
private void DeleteProfile(int id)
@ -42,11 +42,10 @@ namespace NzbDrone.Api.Qualities
_qualityProfileService.Delete(id);
}
private QualityProfileResource Update(QualityProfileResource resource)
private void Update(QualityProfileResource resource)
{
var model = resource.InjectTo<QualityProfile>();
_qualityProfileService.Update(model);
return GetById(resource.Id);
}
private QualityProfileResource GetById(int id)

View File

@ -19,16 +19,15 @@ namespace NzbDrone.Api.Qualities
UpdateResource = Update;
}
private QualitySizeResource Update(QualitySizeResource resource)
private void Update(QualitySizeResource resource)
{
var model = resource.InjectTo<QualitySize>();
_qualityTypeProvider.Update(model);
return GetById(resource.Id);
}
private QualitySizeResource GetById(int id)
{
return ToResource(() => _qualityTypeProvider.Get(id));
return _qualityTypeProvider.Get(id).InjectTo<QualitySizeResource>();
}
private List<QualitySizeResource> GetAll()

View File

@ -19,8 +19,8 @@ namespace NzbDrone.Api.REST
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;
private Func<TResource, int> _createResource;
private Action<TResource> _updateResource;
protected ResourceValidator<TResource> PostValidator { get; private set; }
protected ResourceValidator<TResource> PutValidator { get; private set; }
@ -132,7 +132,7 @@ namespace NzbDrone.Api.REST
}
}
protected Func<TResource, TResource> CreateResource
protected Func<TResource, int> CreateResource
{
private get { return _createResource; }
set
@ -140,36 +140,37 @@ namespace NzbDrone.Api.REST
_createResource = value;
Post[ROOT_ROUTE] = options =>
{
var resource = CreateResource(ReadFromRequest());
return resource.AsResponse(HttpStatusCode.Created);
var id = CreateResource(ReadResourceFromRequest());
return GetResourceById(id).AsResponse(HttpStatusCode.Created);
};
}
}
protected Func<TResource, TResource> UpdateResource
protected Action<TResource> UpdateResource
{
private get { return _updateResource; }
set
{
_updateResource = value;
Put[ROOT_ROUTE] = options =>
{
var resource = UpdateResource(ReadFromRequest());
return resource.AsResponse(HttpStatusCode.Accepted);
};
{
var resource = ReadResourceFromRequest();
UpdateResource(resource);
return GetResourceById(resource.Id).AsResponse(HttpStatusCode.Accepted);
};
Put[ID_ROUTE] = options =>
{
var model = ReadFromRequest();
model.Id = options.Id;
var resource = UpdateResource(model);
return resource.AsResponse(HttpStatusCode.Accepted);
var resource = ReadResourceFromRequest();
resource.Id = options.Id;
UpdateResource(resource);
return GetResourceById(resource.Id).AsResponse(HttpStatusCode.Accepted);
};
}
}
private TResource ReadFromRequest()
protected TResource ReadResourceFromRequest()
{
//TODO: handle when request is null
var resource = Request.Body.FromJson<TResource>();

View File

@ -16,9 +16,9 @@ namespace NzbDrone.Api.RootFolders
DeleteResource = DeleteFolder;
}
private RootFolderResource CreateRootFolder(RootFolderResource rootFolderResource)
private int CreateRootFolder(RootFolderResource rootFolderResource)
{
return ToResource<RootFolder>(_rootFolderService.Add, rootFolderResource);
return GetNewId<RootFolder>(_rootFolderService.Add, rootFolderResource);
}
private List<RootFolderResource> GetRootFolders()

View File

@ -13,7 +13,7 @@ namespace NzbDrone.Api.Seasons
_seasonService = seasonService;
GetResourceAll = GetSeasons;
UpdateResource = SetMonitored;
UpdateResource = Update;
Post["/pass"] = x => SetSeasonPass();
}
@ -27,14 +27,12 @@ namespace NzbDrone.Api.Seasons
return ToListResource<Season>(() => _seasonService.GetSeasonsBySeries(seriesId));
}
return ToListResource<Season>(() => _seasonService.GetAllSeasons());
return ToListResource(() => _seasonService.GetAllSeasons());
}
private SeasonResource SetMonitored(SeasonResource seasonResource)
private void Update(SeasonResource seasonResource)
{
_seasonService.SetMonitored(seasonResource.SeriesId, seasonResource.SeasonNumber, seasonResource.Monitored);
return seasonResource;
}
private List<SeasonResource> SetSeasonPass()

View File

@ -66,18 +66,14 @@ namespace NzbDrone.Api.Series
return seriesResources;
}
private SeriesResource AddSeries(SeriesResource seriesResource)
private int AddSeries(SeriesResource seriesResource)
{
return ToResource<Core.Tv.Series>(_seriesService.AddSeries, seriesResource);
return GetNewId<Core.Tv.Series>(_seriesService.AddSeries, seriesResource);
}
private SeriesResource UpdateSeries(SeriesResource seriesResource)
private void UpdateSeries(SeriesResource seriesResource)
{
var resource = ToResource<Core.Tv.Series>(_seriesService.UpdateSeries, seriesResource);
MapCoversToLocal(resource);
FetchAndLinkSeriesStatistics(resource);
return resource;
GetNewId<Core.Tv.Series>(_seriesService.UpdateSeries, seriesResource);
}
private void DeleteSeries(int id)

View File

@ -1,4 +1,4 @@
'use strict';
'use strict';
define(
[
'Settings/SettingsModelBase'

View File

@ -19,13 +19,13 @@ define(
'change .x-rename-episodes': '_setNamingOptionsVisibility'
},
onRender: function(){
if(!this.model.get('renameEpisodes')){
onRender: function () {
if (!this.model.get('renameEpisodes')) {
this.ui.namingOptions.hide();
}
this.listenTo(this.model, 'change', this._buildExamples);
this._buildExamples();
this.listenTo(this.model, 'change', this._updateExamples);
this._updateExamples();
},
_setNamingOptionsVisibility: function () {
@ -39,16 +39,14 @@ define(
}
},
_buildExamples: function () {
_updateExamples: function () {
var self = this;
var data = this.model.toJSON();
data.id = 0;
var promise = $.ajax({
type: 'POST',
url : window.ApiRoot + '/naming',
data: JSON.stringify(data)
type: 'GET',
url : window.ApiRoot + '/config/naming/samples',
data: this.model.toJSON()
});
promise.done(function (result) {