Updated Nancy to 2.0

pull/3763/head
ta264 5 years ago committed by Qstick
parent 6c4e3b1fd5
commit 79cf3079c3

@ -40,7 +40,7 @@ export default function createAjaxRequest(originalAjaxOptions) {
} }
} }
const ajaxOptions = { ...originalAjaxOptions }; const ajaxOptions = { dataType: 'json', ...originalAjaxOptions };
if (isRelative(ajaxOptions)) { if (isRelative(ajaxOptions)) {
moveBodyToQuery(ajaxOptions); moveBodyToQuery(ajaxOptions);

@ -26,12 +26,12 @@ namespace NzbDrone.Api.Calendar
_movieService = movieService; _movieService = movieService;
_tagService = tagService; _tagService = tagService;
Get["/NzbDrone.ics"] = options => GetCalendarFeed(); Get("/NzbDrone.ics", options => GetCalendarFeed());
Get["/Sonarr.ics"] = options => GetCalendarFeed(); Get("/Sonarr.ics", options => GetCalendarFeed());
Get["/Radarr.ics"] = options => GetCalendarFeed(); Get("/Radarr.ics", options => GetCalendarFeed());
} }
private Response GetCalendarFeed() private object GetCalendarFeed()
{ {
var pastDays = 7; var pastDays = 7;
var futureDays = 28; var futureDays = 28;

@ -2,13 +2,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentValidation; using FluentValidation;
using FluentValidation.Results; using FluentValidation.Results;
using Nancy.Responses;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Organizer; using NzbDrone.Core.Organizer;
using Nancy.ModelBinding; using Nancy.ModelBinding;
using Radarr.Http.Extensions;
using Radarr.Http; using Radarr.Http;
using Radarr.Http.Mapping;
namespace NzbDrone.Api.Config namespace NzbDrone.Api.Config
{ {
@ -33,7 +30,7 @@ namespace NzbDrone.Api.Config
GetResourceById = GetNamingConfig; GetResourceById = GetNamingConfig;
UpdateResource = UpdateNamingConfig; UpdateResource = UpdateNamingConfig;
Get["/samples"] = x => GetExamples(this.Bind<NamingConfigResource>()); Get("/samples", x => GetExamples(this.Bind<NamingConfigResource>()));
SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 5); SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 5);
SharedValidator.RuleFor(c => c.StandardMovieFormat).ValidMovieFormat(); SharedValidator.RuleFor(c => c.StandardMovieFormat).ValidMovieFormat();
@ -67,7 +64,7 @@ namespace NzbDrone.Api.Config
return GetNamingConfig(); return GetNamingConfig();
} }
private JsonResponse<NamingSampleResource> GetExamples(NamingConfigResource config) private object GetExamples(NamingConfigResource config)
{ {
var nameSpec = config.ToModel(); var nameSpec = config.ToModel();
var sampleResource = new NamingSampleResource(); var sampleResource = new NamingSampleResource();
@ -82,7 +79,7 @@ namespace NzbDrone.Api.Config
? "Invalid format" ? "Invalid format"
: _filenameSampleService.GetMovieFolderSample(nameSpec); : _filenameSampleService.GetMovieFolderSample(nameSpec);
return sampleResource.AsResponse(); return sampleResource;
} }
private void ValidateFormatResult(NamingConfig nameSpec) private void ValidateFormatResult(NamingConfig nameSpec)

@ -23,49 +23,49 @@ namespace NzbDrone.Api.FileSystem
_fileSystemLookupService = fileSystemLookupService; _fileSystemLookupService = fileSystemLookupService;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_diskScanService = diskScanService; _diskScanService = diskScanService;
Get["/"] = x => GetContents(); Get("/", x => GetContents());
Get["/type"] = x => GetEntityType(); Get("/type", x => GetEntityType());
Get["/mediafiles"] = x => GetMediaFiles(); Get("/mediafiles", x => GetMediaFiles());
} }
private Response GetContents() private object GetContents()
{ {
var pathQuery = Request.Query.path; var pathQuery = Request.Query.path;
var includeFiles = Request.GetBooleanQueryParameter("includeFiles"); var includeFiles = Request.GetBooleanQueryParameter("includeFiles");
var allowFoldersWithoutTrailingSlashes = Request.GetBooleanQueryParameter("allowFoldersWithoutTrailingSlashes"); var allowFoldersWithoutTrailingSlashes = Request.GetBooleanQueryParameter("allowFoldersWithoutTrailingSlashes");
return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles, allowFoldersWithoutTrailingSlashes).AsResponse(); return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles, allowFoldersWithoutTrailingSlashes);
} }
private Response GetEntityType() private object GetEntityType()
{ {
var pathQuery = Request.Query.path; var pathQuery = Request.Query.path;
var path = (string)pathQuery.Value; var path = (string)pathQuery.Value;
if (_diskProvider.FileExists(path)) if (_diskProvider.FileExists(path))
{ {
return new { type = "file" }.AsResponse(); return new { type = "file" };
} }
//Return folder even if it doesn't exist on disk to avoid leaking anything from the UI about the underlying system //Return folder even if it doesn't exist on disk to avoid leaking anything from the UI about the underlying system
return new { type = "folder" }.AsResponse(); return new { type = "folder" };
} }
private Response GetMediaFiles() private object GetMediaFiles()
{ {
var pathQuery = Request.Query.path; var pathQuery = Request.Query.path;
var path = (string)pathQuery.Value; var path = (string)pathQuery.Value;
if (!_diskProvider.FolderExists(path)) if (!_diskProvider.FolderExists(path))
{ {
return new string[0].AsResponse(); return new string[0];
} }
return _diskScanService.GetVideoFiles(path).Select(f => new { return _diskScanService.GetVideoFiles(path).Select(f => new {
Path = f, Path = f,
RelativePath = path.GetRelativePath(f), RelativePath = path.GetRelativePath(f),
Name = Path.GetFileName(f) Name = Path.GetFileName(f)
}).AsResponse(); });
} }
} }
} }

@ -27,7 +27,7 @@ namespace NzbDrone.Api.History
_failedDownloadService = failedDownloadService; _failedDownloadService = failedDownloadService;
GetResourcePaged = GetHistory; GetResourcePaged = GetHistory;
Post["/failed"] = x => MarkAsFailed(); Post("/failed", x => MarkAsFailed());
} }
protected HistoryResource MapToResource(Core.History.History model) protected HistoryResource MapToResource(Core.History.History model)
@ -64,11 +64,11 @@ namespace NzbDrone.Api.History
return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource); return ApplyToPage(_historyService.Paged, pagingSpec, MapToResource);
} }
private Response MarkAsFailed() private object MarkAsFailed()
{ {
var id = (int)Request.Form.Id; var id = (int)Request.Form.Id;
_failedDownloadService.MarkAsFailed(id); _failedDownloadService.MarkAsFailed(id);
return new object().AsResponse(); return new object();
} }
} }
} }

@ -43,7 +43,7 @@ namespace NzbDrone.Api.Indexers
_logger = logger; _logger = logger;
GetResourceAll = GetReleases; GetResourceAll = GetReleases;
Post["/"] = x => DownloadRelease(this.Bind<ReleaseResource>()); Post("/", x => DownloadRelease(this.Bind<ReleaseResource>()));
//PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true); //PostValidator.RuleFor(s => s.DownloadAllowed).Equal(true);
PostValidator.RuleFor(s => s.Guid).NotEmpty(); PostValidator.RuleFor(s => s.Guid).NotEmpty();
@ -51,7 +51,7 @@ namespace NzbDrone.Api.Indexers
_remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies"); _remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies");
} }
private Response DownloadRelease(ReleaseResource release) private object DownloadRelease(ReleaseResource release)
{ {
var remoteMovie = _remoteMovieCache.Find(release.Guid); var remoteMovie = _remoteMovieCache.Find(release.Guid);
@ -71,7 +71,7 @@ namespace NzbDrone.Api.Indexers
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed"); throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
} }
return release.AsResponse(); return release;
} }
private List<ReleaseResource> GetReleases() private List<ReleaseResource> GetReleases()

@ -30,7 +30,7 @@ namespace NzbDrone.Api.Indexers
_indexerFactory = indexerFactory; _indexerFactory = indexerFactory;
_logger = logger; _logger = logger;
Post["/push"] = x => ProcessRelease(ReadResourceFromRequest()); Post("/push", x => ProcessRelease(ReadResourceFromRequest()));
PostValidator.RuleFor(s => s.Title).NotEmpty(); PostValidator.RuleFor(s => s.Title).NotEmpty();
PostValidator.RuleFor(s => s.DownloadUrl).NotEmpty(); PostValidator.RuleFor(s => s.DownloadUrl).NotEmpty();
@ -38,7 +38,7 @@ namespace NzbDrone.Api.Indexers
PostValidator.RuleFor(s => s.PublishDate).NotEmpty(); PostValidator.RuleFor(s => s.PublishDate).NotEmpty();
} }
private Response ProcessRelease(ReleaseResource release) private object ProcessRelease(ReleaseResource release)
{ {
_logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl); _logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl);
@ -51,7 +51,7 @@ namespace NzbDrone.Api.Indexers
var decisions = _downloadDecisionMaker.GetRssDecision(new List<ReleaseInfo> { info }); var decisions = _downloadDecisionMaker.GetRssDecision(new List<ReleaseInfo> { info });
_downloadDecisionProcessor.ProcessDecisions(decisions); _downloadDecisionProcessor.ProcessDecisions(decisions);
return MapDecisions(decisions).First().AsResponse(); return MapDecisions(decisions).First();
} }
private void ResolveIndexer(ReleaseInfo release) private void ResolveIndexer(ReleaseInfo release)

@ -26,7 +26,7 @@ namespace NzbDrone.Api.Logs
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
GetResourceAll = GetLogFilesResponse; GetResourceAll = GetLogFilesResponse;
Get[LOGFILE_ROUTE] = options => GetLogFileResponse(options.filename); Get(LOGFILE_ROUTE, options => GetLogFileResponse(options.filename));
} }
private List<LogFileResource> GetLogFilesResponse() private List<LogFileResource> GetLogFilesResponse()
@ -53,7 +53,7 @@ namespace NzbDrone.Api.Logs
return result.OrderByDescending(l => l.LastWriteTime).ToList(); return result.OrderByDescending(l => l.LastWriteTime).ToList();
} }
private Response GetLogFileResponse(string filename) private object GetLogFileResponse(string filename)
{ {
LogManager.Flush(); LogManager.Flush();

@ -22,10 +22,10 @@ namespace NzbDrone.Api.MediaCovers
_appFolderInfo = appFolderInfo; _appFolderInfo = appFolderInfo;
_diskProvider = diskProvider; _diskProvider = diskProvider;
Get[MEDIA_COVER_ROUTE] = options => GetMediaCover(options.seriesId, options.filename); Get(MEDIA_COVER_ROUTE, options => GetMediaCover(options.seriesId, options.filename));
} }
private Response GetMediaCover(int seriesId, string filename) private object GetMediaCover(int seriesId, string filename)
{ {
var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", seriesId.ToString(), filename); var filePath = Path.Combine(_appFolderInfo.GetAppDataPath(), "MediaCover", seriesId.ToString(), filename);

@ -19,11 +19,11 @@ namespace NzbDrone.Api.Movies
{ {
_fetchNetImport = netImport; _fetchNetImport = netImport;
_movieSearch = movieSearch; _movieSearch = movieSearch;
Get["/"] = x => Search(); Get("/", x => Search());
} }
private Response Search() private object Search()
{ {
var results = _fetchNetImport.FetchAndFilter((int) Request.Query.listId, false); var results = _fetchNetImport.FetchAndFilter((int) Request.Query.listId, false);
@ -39,7 +39,7 @@ namespace NzbDrone.Api.Movies
} }
}*/ }*/
return MapToResource(results).AsResponse(); return MapToResource(results);
} }

@ -53,11 +53,11 @@ namespace NzbDrone.Api.Movies
_movieService = movieService; _movieService = movieService;
_profileService = profileService; _profileService = profileService;
_parsingService = parsingService; _parsingService = parsingService;
Get["/"] = x => Search(); Get("/", x => Search());
} }
private Response Search() private object Search()
{ {
if (Request.Query.Id == 0) if (Request.Query.Id == 0)
{ {
@ -166,7 +166,7 @@ namespace NzbDrone.Api.Movies
SortKey = Request.Query.sort_by, SortKey = Request.Query.sort_by,
TotalRecords = total_count - mapped.Where(m => m == null).Count(), TotalRecords = total_count - mapped.Where(m => m == null).Count(),
Records = MapToResource(mapped.Where(m => m != null)).ToList() Records = MapToResource(mapped.Where(m => m != null)).ToList()
}.AsResponse(); };
} }

@ -21,17 +21,17 @@ namespace NzbDrone.Api.Movies
{ {
_searchProxy = searchProxy; _searchProxy = searchProxy;
_netImportFactory = netImportFactory; _netImportFactory = netImportFactory;
Get["/lists"] = x => GetLists(); Get("/lists", x => GetLists());
Get["/{action?recommendations}"] = x => Search(x.action); Get("/{action?recommendations}", x => Search(x.action));
} }
private Response Search(string action) private object Search(string action)
{ {
var imdbResults = _searchProxy.DiscoverNewMovies(action); var imdbResults = _searchProxy.DiscoverNewMovies(action);
return MapToResource(imdbResults).AsResponse(); return MapToResource(imdbResults);
} }
private Response GetLists() private object GetLists()
{ {
var lists = _netImportFactory.Discoverable(); var lists = _netImportFactory.Discoverable();
@ -42,7 +42,7 @@ namespace NzbDrone.Api.Movies
resource.Name = definition.Definition.Name; resource.Name = definition.Definition.Name;
return resource; return resource;
}).AsResponse(); });
} }
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Movies.Movie> movies) private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Movies.Movie> movies)

@ -18,22 +18,22 @@ namespace NzbDrone.Api.Movies
: base("/movie/editor") : base("/movie/editor")
{ {
_movieService = movieService; _movieService = movieService;
Put["/"] = Movie => SaveAll(); Put("/", Movie => SaveAll());
Put["/delete"] = Movie => DeleteSelected(); Put("/delete", Movie => DeleteSelected());
} }
private Response SaveAll() private object SaveAll()
{ {
var resources = Request.Body.FromJson<List<MovieResource>>(); var resources = Request.Body.FromJson<List<MovieResource>>();
var Movie = resources.Select(MovieResource => MovieResource.ToModel(_movieService.GetMovie(MovieResource.Id))).ToList(); var Movie = resources.Select(MovieResource => MovieResource.ToModel(_movieService.GetMovie(MovieResource.Id))).ToList();
return _movieService.UpdateMovie(Movie) return ResponseWithCode(_movieService.UpdateMovie(Movie)
.ToResource() .ToResource()
.AsResponse(HttpStatusCode.Accepted); , HttpStatusCode.Accepted);
} }
private Response DeleteSelected() private object DeleteSelected()
{ {
var deleteFiles = false; var deleteFiles = false;
var addExclusion = false; var addExclusion = false;

@ -20,34 +20,34 @@ namespace NzbDrone.Api.Movies
{ {
_movieInfo = movieInfo; _movieInfo = movieInfo;
_searchProxy = searchProxy; _searchProxy = searchProxy;
Get["/"] = x => Search(); Get("/", x => Search());
Get["/tmdb"] = x => SearchByTmdbId(); Get("/tmdb", x => SearchByTmdbId());
Get["/imdb"] = x => SearchByImdbId(); Get("/imdb", x => SearchByImdbId());
} }
private Response SearchByTmdbId() private object SearchByTmdbId()
{ {
int tmdbId = -1; int tmdbId = -1;
if(Int32.TryParse(Request.Query.tmdbId, out tmdbId)) if(Int32.TryParse(Request.Query.tmdbId, out tmdbId))
{ {
var result = _movieInfo.GetMovieInfo(tmdbId, null, true); var result = _movieInfo.GetMovieInfo(tmdbId, null, true);
return result.ToResource().AsResponse(); return result.ToResource();
} }
throw new BadRequestException("Tmdb Id was not valid"); throw new BadRequestException("Tmdb Id was not valid");
} }
private Response SearchByImdbId() private object SearchByImdbId()
{ {
string imdbId = Request.Query.imdbId; string imdbId = Request.Query.imdbId;
var result = _movieInfo.GetMovieInfo(imdbId); var result = _movieInfo.GetMovieInfo(imdbId);
return result.ToResource().AsResponse(); return result.ToResource();
} }
private Response Search() private object Search()
{ {
var imdbResults = _searchProxy.SearchForNewMovie((string)Request.Query.term); var imdbResults = _searchProxy.SearchForNewMovie((string)Request.Query.term);
return MapToResource(imdbResults).AsResponse(); return MapToResource(imdbResults);
} }
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Movies.Movie> movies) private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Movies.Movie> movies)

@ -54,7 +54,8 @@ namespace NzbDrone.Api.Movies
GetResourceAll = AllMovie; GetResourceAll = AllMovie;
GetResourceById = GetMovie; GetResourceById = GetMovie;
Get[TITLE_SLUG_ROUTE] = GetByTitleSlug; Get(TITLE_SLUG_ROUTE, GetByTitleSlug);
CreateResource = AddMovie; CreateResource = AddMovie;
UpdateResource = UpdateMovie; UpdateResource = UpdateMovie;
DeleteResource = DeleteMovie; DeleteResource = DeleteMovie;
@ -105,7 +106,7 @@ namespace NzbDrone.Api.Movies
return moviesResources; return moviesResources;
} }
private Response GetByTitleSlug(dynamic options) private object GetByTitleSlug(dynamic options)
{ {
string slug; string slug;
try try
@ -120,7 +121,7 @@ namespace NzbDrone.Api.Movies
try try
{ {
return MapToResource(_moviesService.FindByTitleSlug(slug)).AsResponse(HttpStatusCode.OK); return ResponseWithCode(MapToResource(_moviesService.FindByTitleSlug(slug)), HttpStatusCode.OK);
} }
catch (ModelNotFoundException) catch (ModelNotFoundException)
{ {

@ -19,16 +19,16 @@ namespace NzbDrone.Api.NetImport
{ {
_movieService = movieService; _movieService = movieService;
_movieSearch = movieSearch; _movieSearch = movieSearch;
Put["/"] = Movie => SaveAll(); Put("/", Movie => SaveAll());
} }
private Response SaveAll() private object SaveAll()
{ {
var resources = Request.Body.FromJson<List<MovieResource>>(); var resources = Request.Body.FromJson<List<MovieResource>>();
var Movies = resources.Select(MovieResource => _movieSearch.MapMovieToTmdbMovie(MovieResource.ToModel())).Where(m => m != null).DistinctBy(m => m.TmdbId).ToList(); var Movies = resources.Select(MovieResource => _movieSearch.MapMovieToTmdbMovie(MovieResource.ToModel())).Where(m => m != null).DistinctBy(m => m.TmdbId).ToList();
return _movieService.AddMovies(Movies).ToResource().AsResponse(HttpStatusCode.Accepted); return ResponseWithCode(_movieService.AddMovies(Movies).ToResource(), HttpStatusCode.Accepted);
} }
} }
} }

@ -1,8 +1,8 @@
using Nancy; using Radarr.Http;
namespace NzbDrone.Api namespace NzbDrone.Api
{ {
public abstract class NzbDroneApiModule : NancyModule public abstract class NzbDroneApiModule : RadarrModule
{ {
protected NzbDroneApiModule(string resource) protected NzbDroneApiModule(string resource)
: base("/api/" + resource.Trim('/')) : base("/api/" + resource.Trim('/'))

@ -1,8 +1,8 @@
using Nancy; using Radarr.Http;
namespace NzbDrone.Api namespace NzbDrone.Api
{ {
public abstract class NzbDroneFeedModule : NancyModule public abstract class NzbDroneFeedModule : RadarrModule
{ {
protected NzbDroneFeedModule(string resource) protected NzbDroneFeedModule(string resource)
: base("/feed/" + resource.Trim('/')) : base("/feed/" + resource.Trim('/'))

@ -8,13 +8,13 @@ namespace NzbDrone.Api.Profiles
public LegacyProfileModule() public LegacyProfileModule()
: base("qualityprofile") : base("qualityprofile")
{ {
Get["/"] = x => Get("/", x =>
{ {
string queryString = ConvertQueryParams(Request.Query); string queryString = ConvertQueryParams(Request.Query);
var url = string.Format("/api/profile?{0}", queryString); var url = string.Format("/api/profile?{0}", queryString);
return Response.AsRedirect(url); return Response.AsRedirect(url);
}; });
} }
private string ConvertQueryParams(DynamicDictionary query) private string ConvertQueryParams(DynamicDictionary query)

@ -26,9 +26,9 @@ namespace NzbDrone.Api
{ {
_providerFactory = providerFactory; _providerFactory = providerFactory;
Get["schema"] = x => GetTemplates(); Get("schema", x => GetTemplates());
Post["test"] = x => Test(ReadResourceFromRequest(true)); Post("test", x => Test(ReadResourceFromRequest(true)));
Post["action/{action}"] = x => RequestAction(x.action, ReadResourceFromRequest(true)); Post("action/{action}", x => RequestAction(x.action, ReadResourceFromRequest(true)));
GetResourceAll = GetAll; GetResourceAll = GetAll;
GetResourceById = GetProviderById; GetResourceById = GetProviderById;
@ -145,7 +145,7 @@ namespace NzbDrone.Api
_providerFactory.Delete(id); _providerFactory.Delete(id);
} }
private Response GetTemplates() private object GetTemplates()
{ {
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList(); var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList();
@ -169,10 +169,10 @@ namespace NzbDrone.Api
result.Add(providerResource); result.Add(providerResource);
} }
return result.AsResponse(); return result;
} }
private Response Test(TProviderResource providerResource) private object Test(TProviderResource providerResource)
{ {
// Don't validate when getting the definition so we can validate afterwards (avoids validation being skipped because the provider is disabled) // Don't validate when getting the definition so we can validate afterwards (avoids validation being skipped because the provider is disabled)
var providerDefinition = GetDefinition(providerResource, true, false); var providerDefinition = GetDefinition(providerResource, true, false);
@ -184,7 +184,7 @@ namespace NzbDrone.Api
} }
private Response RequestAction(string action, TProviderResource providerResource) private object RequestAction(string action, TProviderResource providerResource)
{ {
var providerDefinition = GetDefinition(providerResource, true, false); var providerDefinition = GetDefinition(providerResource, true, false);

@ -48,11 +48,11 @@ namespace NzbDrone.Api.Qualities
DeleteResource = DeleteFormat; DeleteResource = DeleteFormat;
Get["/test"] = x => Test(); Get("/test", x => Test());
Post["/test"] = x => TestWithNewModel(); Post("/test", x => TestWithNewModel());
Get["schema"] = x => GetTemplates(); Get("schema", x => GetTemplates());
} }
private int Create(CustomFormatResource customFormatResource) private int Create(CustomFormatResource customFormatResource)
@ -82,7 +82,7 @@ namespace NzbDrone.Api.Qualities
_formatService.Delete(id); _formatService.Delete(id);
} }
private Response GetTemplates() private object GetTemplates()
{ {
return CustomFormatService.Templates.SelectMany(t => return CustomFormatService.Templates.SelectMany(t =>
{ {
@ -92,7 +92,7 @@ namespace NzbDrone.Api.Qualities
r.Simplicity = t.Key; r.Simplicity = t.Key;
return r; return r;
}); });
}).AsResponse(); });
} }
private CustomFormatTestResource Test() private CustomFormatTestResource Test()

@ -1,6 +1,5 @@
using System; using System;
using Nancy; using Nancy;
using Nancy.Responses;
using Radarr.Http.Extensions; using Radarr.Http.Extensions;
using Radarr.Http.REST; using Radarr.Http.REST;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
@ -37,12 +36,12 @@ namespace NzbDrone.Api.Queue
_pendingReleaseService = pendingReleaseService; _pendingReleaseService = pendingReleaseService;
_downloadService = downloadService; _downloadService = downloadService;
Delete[@"/(?<id>[\d]{1,10})"] = x => Remove((int)x.Id); Delete(@"/(?<id>[\d]{1,10})", x => Remove((int)x.Id));
Post["/import"] = x => Import(); Post("/import", x => Import());
Post["/grab"] = x => Grab(); Post("/grab", x => Grab());
} }
private Response Remove(int id) private object Remove(int id)
{ {
var blacklist = false; var blacklist = false;
var blacklistQuery = Request.Query.blacklist; var blacklistQuery = Request.Query.blacklist;
@ -58,7 +57,7 @@ namespace NzbDrone.Api.Queue
{ {
_pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id); _pendingReleaseService.RemovePendingQueueItems(pendingRelease.Id);
return new object().AsResponse(); return new object();
} }
var trackedDownload = GetTrackedDownload(id); var trackedDownload = GetTrackedDownload(id);
@ -82,20 +81,20 @@ namespace NzbDrone.Api.Queue
_failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId); _failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId);
} }
return new object().AsResponse(); return new object();
} }
private JsonResponse<QueueResource> Import() private object Import()
{ {
var resource = Request.Body.FromJson<QueueResource>(); var resource = Request.Body.FromJson<QueueResource>();
var trackedDownload = GetTrackedDownload(resource.Id); var trackedDownload = GetTrackedDownload(resource.Id);
_completedDownloadService.Process(trackedDownload, true); _completedDownloadService.Process(trackedDownload, true);
return resource.AsResponse(); return resource;
} }
private JsonResponse<QueueResource> Grab() private object Grab()
{ {
var resource = Request.Body.FromJson<QueueResource>(); var resource = Request.Body.FromJson<QueueResource>();
@ -108,7 +107,7 @@ namespace NzbDrone.Api.Queue
_downloadService.DownloadReport(pendingRelease.RemoteMovie); _downloadService.DownloadReport(pendingRelease.RemoteMovie);
return resource.AsResponse(); return resource;
} }
private TrackedDownload GetTrackedDownload(int queueId) private TrackedDownload GetTrackedDownload(int queueId)

@ -6,9 +6,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="8.4.0" /> <PackageReference Include="FluentValidation" Version="8.4.0" />
<PackageReference Include="Ical.Net" Version="2.2.32" /> <PackageReference Include="Ical.Net" Version="2.2.32" />
<PackageReference Include="Nancy" Version="1.4.4" /> <PackageReference Include="Nancy" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Basic" Version="1.4.1" /> <PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Forms" Version="1.4.1" /> <PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -37,13 +37,13 @@ namespace NzbDrone.Api.System
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
_database = database; _database = database;
_lifecycleService = lifecycleService; _lifecycleService = lifecycleService;
Get["/status"] = x => GetStatus(); Get("/status", x => GetStatus());
Get["/routes"] = x => GetRoutes(); Get("/routes", x => GetRoutes());
Post["/shutdown"] = x => Shutdown(); Post("/shutdown", x => Shutdown());
Post["/restart"] = x => Restart(); Post("/restart", x => Restart());
} }
private Response GetStatus() private object GetStatus()
{ {
return new return new
{ {
@ -68,24 +68,24 @@ namespace NzbDrone.Api.System
UrlBase = _configFileProvider.UrlBase, UrlBase = _configFileProvider.UrlBase,
RuntimeVersion = _platformInfo.Version, RuntimeVersion = _platformInfo.Version,
RuntimeName = PlatformInfo.Platform RuntimeName = PlatformInfo.Platform
}.AsResponse(); };
} }
private Response GetRoutes() private object GetRoutes()
{ {
return _routeCacheProvider.GetCache().Values.AsResponse(); return _routeCacheProvider.GetCache().Values;
} }
private Response Shutdown() private object Shutdown()
{ {
_lifecycleService.Shutdown(); _lifecycleService.Shutdown();
return "".AsResponse(); return "";
} }
private Response Restart() private object Restart()
{ {
_lifecycleService.Restart(); _lifecycleService.Restart();
return "".AsResponse(); return "";
} }
} }
} }

@ -7,13 +7,13 @@ namespace NzbDrone.Api.Wanted
{ {
public LegacyMissingModule() : base("missing") public LegacyMissingModule() : base("missing")
{ {
Get["/"] = x => Get("/", x =>
{ {
string queryString = ConvertQueryParams(Request.Query); string queryString = ConvertQueryParams(Request.Query);
var url = string.Format("/api/wanted/missing?{0}", queryString); var url = string.Format("/api/wanted/missing?{0}", queryString);
return Response.AsRedirect(url); return Response.AsRedirect(url);
}; });
} }
private string ConvertQueryParams(DynamicDictionary query) private string ConvertQueryParams(DynamicDictionary query)

@ -3,7 +3,6 @@ using Nancy.Bootstrapper;
using Radarr.Http; using Radarr.Http;
using NzbDrone.Common.Composition; using NzbDrone.Common.Composition;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Http.Dispatchers;
using NzbDrone.SignalR; using NzbDrone.SignalR;
namespace Radarr.Host namespace Radarr.Host

@ -5,7 +5,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNet.SignalR.SelfHost" Version="2.4.1" /> <PackageReference Include="Microsoft.AspNet.SignalR.SelfHost" Version="2.4.1" />
<PackageReference Include="Nancy.Owin" Version="1.4.1" /> <PackageReference Include="Nancy.Owin" Version="2.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\NzbDrone.Api\Radarr.Api.csproj" /> <ProjectReference Include="..\NzbDrone.Api\Radarr.Api.csproj" />

@ -26,10 +26,10 @@ namespace Radarr.Api.V2.Calendar
_movieService = movieService; _movieService = movieService;
_tagService = tagService; _tagService = tagService;
Get["/Radarr.ics"] = options => GetCalendarFeed(); Get("/Radarr.ics", options => GetCalendarFeed());
} }
private Response GetCalendarFeed() private object GetCalendarFeed()
{ {
var pastDays = 7; var pastDays = 7;
var futureDays = 28; var futureDays = 28;

@ -2,13 +2,10 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentValidation; using FluentValidation;
using FluentValidation.Results; using FluentValidation.Results;
using Nancy.Responses;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Organizer; using NzbDrone.Core.Organizer;
using Nancy.ModelBinding; using Nancy.ModelBinding;
using Radarr.Http.Extensions;
using Radarr.Http; using Radarr.Http;
using Radarr.Http.Mapping;
namespace Radarr.Api.V2.Config namespace Radarr.Api.V2.Config
{ {
@ -33,7 +30,7 @@ namespace Radarr.Api.V2.Config
GetResourceById = GetNamingConfig; GetResourceById = GetNamingConfig;
UpdateResource = UpdateNamingConfig; UpdateResource = UpdateNamingConfig;
Get["/examples"] = x => GetExamples(this.Bind<NamingConfigResource>()); Get("/examples", x => GetExamples(this.Bind<NamingConfigResource>()));
SharedValidator.RuleFor(c => c.StandardMovieFormat).ValidMovieFormat(); SharedValidator.RuleFor(c => c.StandardMovieFormat).ValidMovieFormat();
SharedValidator.RuleFor(c => c.MovieFolderFormat).ValidMovieFolderFormat(); SharedValidator.RuleFor(c => c.MovieFolderFormat).ValidMovieFolderFormat();
@ -66,7 +63,7 @@ namespace Radarr.Api.V2.Config
return GetNamingConfig(); return GetNamingConfig();
} }
private JsonResponse<NamingExampleResource> GetExamples(NamingConfigResource config) private object GetExamples(NamingConfigResource config)
{ {
if (config.Id == 0) if (config.Id == 0)
{ {
@ -86,7 +83,7 @@ namespace Radarr.Api.V2.Config
? "Invalid format" ? "Invalid format"
: _filenameSampleService.GetMovieFolderSample(nameSpec); : _filenameSampleService.GetMovieFolderSample(nameSpec);
return sampleResource.AsResponse(); return sampleResource;
} }
private void ValidateFormatResult(NamingConfig nameSpec) private void ValidateFormatResult(NamingConfig nameSpec)

@ -23,49 +23,49 @@ namespace Radarr.Api.V2.FileSystem
_fileSystemLookupService = fileSystemLookupService; _fileSystemLookupService = fileSystemLookupService;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_diskScanService = diskScanService; _diskScanService = diskScanService;
Get["/"] = x => GetContents(); Get("/", x => GetContents());
Get["/type"] = x => GetEntityType(); Get("/type", x => GetEntityType());
Get["/mediafiles"] = x => GetMediaFiles(); Get("/mediafiles", x => GetMediaFiles());
} }
private Response GetContents() private object GetContents()
{ {
var pathQuery = Request.Query.path; var pathQuery = Request.Query.path;
var includeFiles = Request.GetBooleanQueryParameter("includeFiles"); var includeFiles = Request.GetBooleanQueryParameter("includeFiles");
var allowFoldersWithoutTrailingSlashes = Request.GetBooleanQueryParameter("allowFoldersWithoutTrailingSlashes"); var allowFoldersWithoutTrailingSlashes = Request.GetBooleanQueryParameter("allowFoldersWithoutTrailingSlashes");
return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles, allowFoldersWithoutTrailingSlashes).AsResponse(); return _fileSystemLookupService.LookupContents((string)pathQuery.Value, includeFiles, allowFoldersWithoutTrailingSlashes);
} }
private Response GetEntityType() private object GetEntityType()
{ {
var pathQuery = Request.Query.path; var pathQuery = Request.Query.path;
var path = (string)pathQuery.Value; var path = (string)pathQuery.Value;
if (_diskProvider.FileExists(path)) if (_diskProvider.FileExists(path))
{ {
return new { type = "file" }.AsResponse(); return new { type = "file" };
} }
//Return folder even if it doesn't exist on disk to avoid leaking anything from the UI about the underlying system //Return folder even if it doesn't exist on disk to avoid leaking anything from the UI about the underlying system
return new { type = "folder" }.AsResponse(); return new { type = "folder" };
} }
private Response GetMediaFiles() private object GetMediaFiles()
{ {
var pathQuery = Request.Query.path; var pathQuery = Request.Query.path;
var path = (string)pathQuery.Value; var path = (string)pathQuery.Value;
if (!_diskProvider.FolderExists(path)) if (!_diskProvider.FolderExists(path))
{ {
return new string[0].AsResponse(); return new string[0];
} }
return _diskScanService.GetVideoFiles(path).Select(f => new { return _diskScanService.GetVideoFiles(path).Select(f => new {
Path = f, Path = f,
RelativePath = path.GetRelativePath(f), RelativePath = path.GetRelativePath(f),
Name = Path.GetFileName(f) Name = Path.GetFileName(f)
}).AsResponse(); });
} }
} }
} }

@ -28,9 +28,9 @@ namespace Radarr.Api.V2.History
_failedDownloadService = failedDownloadService; _failedDownloadService = failedDownloadService;
GetResourcePaged = GetHistory; GetResourcePaged = GetHistory;
Get["/since"] = x => GetHistorySince(); Get("/since", x => GetHistorySince());
Get["/movie"] = x => GetMovieHistory(); Get("/movie", x => GetMovieHistory());
Post["/failed"] = x => MarkAsFailed(); Post("/failed", x => MarkAsFailed());
} }
protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeMovie) protected HistoryResource MapToResource(NzbDrone.Core.History.History model, bool includeMovie)
@ -117,11 +117,11 @@ namespace Radarr.Api.V2.History
return _historyService.GetByMovieId(movieId, eventType).Select(h => MapToResource(h, includeMovie)).ToList(); return _historyService.GetByMovieId(movieId, eventType).Select(h => MapToResource(h, includeMovie)).ToList();
} }
private Response MarkAsFailed() private object MarkAsFailed()
{ {
var id = (int)Request.Form.Id; var id = (int)Request.Form.Id;
_failedDownloadService.MarkAsFailed(id); _failedDownloadService.MarkAsFailed(id);
return new object().AsResponse(); return new object();
} }
} }
} }

@ -47,12 +47,12 @@ namespace Radarr.Api.V2.Indexers
PostValidator.RuleFor(s => s.Guid).NotEmpty(); PostValidator.RuleFor(s => s.Guid).NotEmpty();
GetResourceAll = GetReleases; GetResourceAll = GetReleases;
Post["/"] = x => DownloadRelease(ReadResourceFromRequest()); Post("/", x => DownloadRelease(ReadResourceFromRequest()));
_remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies"); _remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies");
} }
private Response DownloadRelease(ReleaseResource release) private object DownloadRelease(ReleaseResource release)
{ {
var remoteMovie = _remoteMovieCache.Find(GetCacheKey(release)); var remoteMovie = _remoteMovieCache.Find(GetCacheKey(release));
@ -73,7 +73,7 @@ namespace Radarr.Api.V2.Indexers
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed"); throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
} }
return release.AsResponse(); return release;
} }
private List<ReleaseResource> GetReleases() private List<ReleaseResource> GetReleases()

@ -36,10 +36,10 @@ namespace Radarr.Api.V2.Indexers
PostValidator.RuleFor(s => s.Protocol).NotEmpty(); PostValidator.RuleFor(s => s.Protocol).NotEmpty();
PostValidator.RuleFor(s => s.PublishDate).NotEmpty(); PostValidator.RuleFor(s => s.PublishDate).NotEmpty();
Post["/push"] = x => ProcessRelease(ReadResourceFromRequest()); Post("/push", x => ProcessRelease(ReadResourceFromRequest()));
} }
private Response ProcessRelease(ReleaseResource release) private object ProcessRelease(ReleaseResource release)
{ {
_logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl); _logger.Info("Release pushed: {0} - {1}", release.Title, release.DownloadUrl);
@ -59,7 +59,7 @@ namespace Radarr.Api.V2.Indexers
throw new ValidationException(new List<ValidationFailure>{ new ValidationFailure("Title", "Unable to parse", release.Title) }); throw new ValidationException(new List<ValidationFailure>{ new ValidationFailure("Title", "Unable to parse", release.Title) });
} }
return MapDecisions(new [] { firstDecision }).AsResponse(); return MapDecisions(new [] { firstDecision });
} }
private void ResolveIndexer(ReleaseInfo release) private void ResolveIndexer(ReleaseInfo release)

@ -26,7 +26,7 @@ namespace Radarr.Api.V2.Logs
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
GetResourceAll = GetLogFilesResponse; GetResourceAll = GetLogFilesResponse;
Get[LOGFILE_ROUTE] = options => GetLogFileResponse(options.filename); Get(LOGFILE_ROUTE, options => GetLogFileResponse(options.filename));
} }
private List<LogFileResource> GetLogFilesResponse() private List<LogFileResource> GetLogFilesResponse()
@ -53,7 +53,7 @@ namespace Radarr.Api.V2.Logs
return result.OrderByDescending(l => l.LastWriteTime).ToList(); return result.OrderByDescending(l => l.LastWriteTime).ToList();
} }
private Response GetLogFileResponse(string filename) private object GetLogFileResponse(string filename)
{ {
LogManager.Flush(); LogManager.Flush();

@ -45,8 +45,8 @@ namespace Radarr.Api.V2.MovieFiles
UpdateResource = SetMovieFile; UpdateResource = SetMovieFile;
DeleteResource = DeleteMovieFile; DeleteResource = DeleteMovieFile;
Put["/editor"] = movieFiles => SetMovieFile(); Put("/editor", movieFiles => SetMovieFile());
Delete["/bulk"] = movieFiles => DeleteMovieFiles(); Delete("/bulk", movieFiles => DeleteMovieFiles());
} }
private MovieFileResource GetMovieFile(int id) private MovieFileResource GetMovieFile(int id)
@ -100,7 +100,7 @@ namespace Radarr.Api.V2.MovieFiles
_mediaFileService.Update(movieFile); _mediaFileService.Update(movieFile);
} }
private Response SetMovieFile() private object SetMovieFile()
{ {
var resource = Request.Body.FromJson<MovieFileListResource>(); var resource = Request.Body.FromJson<MovieFileListResource>();
var movieFiles = _mediaFileService.GetMovies(resource.MovieFileIds); var movieFiles = _mediaFileService.GetMovies(resource.MovieFileIds);
@ -123,8 +123,8 @@ namespace Radarr.Api.V2.MovieFiles
var movie = _movieService.GetMovie(movieFiles.First().MovieId); var movie = _movieService.GetMovie(movieFiles.First().MovieId);
return movieFiles.ConvertAll(f => f.ToResource(movie, _qualityUpgradableSpecification)) return ResponseWithCode(movieFiles.ConvertAll(f => f.ToResource(movie, _qualityUpgradableSpecification))
.AsResponse(HttpStatusCode.Accepted); , HttpStatusCode.Accepted);
} }
private void DeleteMovieFile(int id) private void DeleteMovieFile(int id)
@ -140,7 +140,7 @@ namespace Radarr.Api.V2.MovieFiles
//_mediaFileDeletionService.Delete(series, episodeFile); //_mediaFileDeletionService.Delete(series, episodeFile);
} }
private Response DeleteMovieFiles() private object DeleteMovieFiles()
{ {
var resource = Request.Body.FromJson<MovieFileListResource>(); var resource = Request.Body.FromJson<MovieFileListResource>();
var movieFiles = _mediaFileService.GetMovies(resource.MovieFileIds); var movieFiles = _mediaFileService.GetMovies(resource.MovieFileIds);
@ -156,7 +156,7 @@ namespace Radarr.Api.V2.MovieFiles
//_mediaFileDeletionService.DeleteEpisodeFile(movie, movieFile); //_mediaFileDeletionService.DeleteEpisodeFile(movie, movieFile);
} }
return new object().AsResponse(); return new object();
} }
public void Handle(MovieFileAddedEvent message) public void Handle(MovieFileAddedEvent message)

@ -20,11 +20,11 @@ namespace Radarr.Api.V2.Movies
{ {
_fetchNetImport = netImport; _fetchNetImport = netImport;
_movieSearch = movieSearch; _movieSearch = movieSearch;
Get["/"] = x => Search(); Get("/", x => Search());
} }
private Response Search() private object Search()
{ {
var results = _fetchNetImport.FetchAndFilter((int) Request.Query.listId, false); var results = _fetchNetImport.FetchAndFilter((int) Request.Query.listId, false);
@ -40,7 +40,7 @@ namespace Radarr.Api.V2.Movies
} }
}*/ }*/
return MapToResource(results).AsResponse(); return MapToResource(results);
} }

@ -22,17 +22,17 @@ namespace Radarr.Api.V2.Movies
{ {
_searchProxy = searchProxy; _searchProxy = searchProxy;
_netImportFactory = netImportFactory; _netImportFactory = netImportFactory;
Get["/lists"] = x => GetLists(); Get("/lists", x => GetLists());
Get["/{action?recommendations}"] = x => Search(x.action); Get("/{action?recommendations}", x => Search(x.action));
} }
private Response Search(string action) private object Search(string action)
{ {
var imdbResults = _searchProxy.DiscoverNewMovies(action); var imdbResults = _searchProxy.DiscoverNewMovies(action);
return MapToResource(imdbResults).AsResponse(); return MapToResource(imdbResults);
} }
private Response GetLists() private object GetLists()
{ {
var lists = _netImportFactory.Discoverable(); var lists = _netImportFactory.Discoverable();
@ -43,7 +43,7 @@ namespace Radarr.Api.V2.Movies
resource.Name = definition.Definition.Name; resource.Name = definition.Definition.Name;
return resource; return resource;
}).AsResponse(); });
} }
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Movie> movies) private static IEnumerable<MovieResource> MapToResource(IEnumerable<Movie> movies)

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Nancy; using Nancy;
using Nancy.Responses;
using Radarr.Http.Extensions; using Radarr.Http.Extensions;
using Radarr.Http.REST;
using NzbDrone.Core.Movies; using NzbDrone.Core.Movies;
using Radarr.Http.Mapping;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Movies.Commands; using NzbDrone.Core.Movies.Commands;
using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Commands;
@ -23,11 +19,11 @@ namespace Radarr.Api.V2.Movies
{ {
_movieService = movieService; _movieService = movieService;
_commandQueueManager = commandQueueManager; _commandQueueManager = commandQueueManager;
Put["/"] = movie => SaveAll(); Put("/", movie => SaveAll());
Delete["/"] = movie => DeleteMovies(); Delete("/", movie => DeleteMovies());
} }
private Response SaveAll() private object SaveAll()
{ {
var resource = Request.Body.FromJson<MovieEditorResource>(); var resource = Request.Body.FromJson<MovieEditorResource>();
var moviesToUpdate = _movieService.GetMovies(resource.MovieIds); var moviesToUpdate = _movieService.GetMovies(resource.MovieIds);
@ -84,12 +80,12 @@ namespace Radarr.Api.V2.Movies
}); });
} }
return _movieService.UpdateMovie(moviesToUpdate) return ResponseWithCode(_movieService.UpdateMovie(moviesToUpdate)
.ToResource() .ToResource()
.AsResponse(HttpStatusCode.Accepted); , HttpStatusCode.Accepted);
} }
private Response DeleteMovies() private object DeleteMovies()
{ {
var resource = Request.Body.FromJson<MovieEditorResource>(); var resource = Request.Body.FromJson<MovieEditorResource>();
@ -98,7 +94,7 @@ namespace Radarr.Api.V2.Movies
_movieService.DeleteMovie(id, false, false); _movieService.DeleteMovie(id, false, false);
} }
return new object().AsResponse(); return new object();
} }
} }
} }

@ -14,16 +14,16 @@ namespace Radarr.Api.V2.Movies
: base("/movie/import") : base("/movie/import")
{ {
_movieService = movieService; _movieService = movieService;
Post["/"] = x => Import(); Post("/", x => Import());
} }
private Response Import() private object Import()
{ {
var resource = Request.Body.FromJson<List<MovieResource>>(); var resource = Request.Body.FromJson<List<MovieResource>>();
var newSeries = resource.ToModel(); var newSeries = resource.ToModel();
return _movieService.AddMovies(newSeries).ToResource().AsResponse(); return _movieService.AddMovies(newSeries).ToResource();
} }
} }
} }

@ -21,34 +21,34 @@ namespace Radarr.Api.V2.Movies
{ {
_movieInfo = movieInfo; _movieInfo = movieInfo;
_searchProxy = searchProxy; _searchProxy = searchProxy;
Get["/"] = x => Search(); Get("/", x => Search());
Get["/tmdb"] = x => SearchByTmdbId(); Get("/tmdb", x => SearchByTmdbId());
Get["/imdb"] = x => SearchByImdbId(); Get("/imdb", x => SearchByImdbId());
} }
private Response SearchByTmdbId() private object SearchByTmdbId()
{ {
int tmdbId = -1; int tmdbId = -1;
if(Int32.TryParse(Request.Query.tmdbId, out tmdbId)) if(Int32.TryParse(Request.Query.tmdbId, out tmdbId))
{ {
var result = _movieInfo.GetMovieInfo(tmdbId, null, true); var result = _movieInfo.GetMovieInfo(tmdbId, null, true);
return result.ToResource().AsResponse(); return result.ToResource();
} }
throw new BadRequestException("Tmdb Id was not valid"); throw new BadRequestException("Tmdb Id was not valid");
} }
private Response SearchByImdbId() private object SearchByImdbId()
{ {
string imdbId = Request.Query.imdbId; string imdbId = Request.Query.imdbId;
var result = _movieInfo.GetMovieInfo(imdbId); var result = _movieInfo.GetMovieInfo(imdbId);
return result.ToResource().AsResponse(); return result.ToResource();
} }
private Response Search() private object Search()
{ {
var imdbResults = _searchProxy.SearchForNewMovie((string)Request.Query.term); var imdbResults = _searchProxy.SearchForNewMovie((string)Request.Query.term);
return MapToResource(imdbResults).AsResponse(); return MapToResource(imdbResults);
} }
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Movie> movies) private static IEnumerable<MovieResource> MapToResource(IEnumerable<Movie> movies)

@ -19,16 +19,16 @@ namespace Radarr.Api.V2.NetImport
{ {
_movieService = movieService; _movieService = movieService;
_movieSearch = movieSearch; _movieSearch = movieSearch;
Put["/"] = Movie => SaveAll(); Put("/", Movie => SaveAll());
} }
private Response SaveAll() private object SaveAll()
{ {
var resources = Request.Body.FromJson<List<MovieResource>>(); var resources = Request.Body.FromJson<List<MovieResource>>();
var Movies = resources.Select(MovieResource => _movieSearch.MapMovieToTmdbMovie(MovieResource.ToModel())).Where(m => m != null).DistinctBy(m => m.TmdbId).ToList(); var Movies = resources.Select(MovieResource => _movieSearch.MapMovieToTmdbMovie(MovieResource.ToModel())).Where(m => m != null).DistinctBy(m => m.TmdbId).ToList();
return _movieService.AddMovies(Movies).ToResource().AsResponse(HttpStatusCode.Accepted); return ResponseWithCode(_movieService.AddMovies(Movies).ToResource(), HttpStatusCode.Accepted);
} }
} }
} }

@ -26,10 +26,10 @@ namespace Radarr.Api.V2
_providerFactory = providerFactory; _providerFactory = providerFactory;
_resourceMapper = resourceMapper; _resourceMapper = resourceMapper;
Get["schema"] = x => GetTemplates(); Get("schema", x => GetTemplates());
Post["test"] = x => Test(ReadResourceFromRequest(true)); Post("test", x => Test(ReadResourceFromRequest(true)));
Post["testall"] = x => TestAll(); Post("testall", x => TestAll());
Post["action/{action}"] = x => RequestAction(x.action, ReadResourceFromRequest(true)); Post("action/{action}", x => RequestAction(x.action, ReadResourceFromRequest(true)));
GetResourceAll = GetAll; GetResourceAll = GetAll;
GetResourceById = GetProviderById; GetResourceById = GetProviderById;
@ -112,7 +112,7 @@ namespace Radarr.Api.V2
_providerFactory.Delete(id); _providerFactory.Delete(id);
} }
private Response GetTemplates() private object GetTemplates()
{ {
var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList(); var defaultDefinitions = _providerFactory.GetDefaultDefinitions().OrderBy(p => p.ImplementationName).ToList();
@ -133,10 +133,10 @@ namespace Radarr.Api.V2
result.Add(providerResource); result.Add(providerResource);
} }
return result.AsResponse(); return result;
} }
private Response Test(TProviderResource providerResource) private object Test(TProviderResource providerResource)
{ {
var providerDefinition = GetDefinition(providerResource, true); var providerDefinition = GetDefinition(providerResource, true);
@ -145,7 +145,7 @@ namespace Radarr.Api.V2
return "{}"; return "{}";
} }
private Response TestAll() private object TestAll()
{ {
var providerDefinitions = _providerFactory.All() var providerDefinitions = _providerFactory.All()
.Where(c => c.Settings.Validate().IsValid && c.Enable) .Where(c => c.Settings.Validate().IsValid && c.Enable)
@ -163,10 +163,10 @@ namespace Radarr.Api.V2
}); });
} }
return result.AsResponse(result.Any(c => !c.IsValid) ? HttpStatusCode.BadRequest : HttpStatusCode.OK); return ResponseWithCode(result, result.Any(c => !c.IsValid) ? HttpStatusCode.BadRequest : HttpStatusCode.OK);
} }
private Response RequestAction(string action, TProviderResource providerResource) private object RequestAction(string action, TProviderResource providerResource)
{ {
var providerDefinition = GetDefinition(providerResource, true, false); var providerDefinition = GetDefinition(providerResource, true, false);

@ -48,11 +48,11 @@ namespace Radarr.Api.V2.Qualities
DeleteResource = DeleteFormat; DeleteResource = DeleteFormat;
Get["/test"] = x => Test(); Get("/test", x => Test());
Post["/test"] = x => TestWithNewModel(); Post("/test", x => TestWithNewModel());
Get["schema"] = x => GetTemplates(); Get("schema", x => GetTemplates());
} }
private int Create(CustomFormatResource customFormatResource) private int Create(CustomFormatResource customFormatResource)
@ -82,7 +82,7 @@ namespace Radarr.Api.V2.Qualities
_formatService.Delete(id); _formatService.Delete(id);
} }
private Response GetTemplates() private object GetTemplates()
{ {
return CustomFormatService.Templates.SelectMany(t => return CustomFormatService.Templates.SelectMany(t =>
{ {
@ -92,7 +92,7 @@ namespace Radarr.Api.V2.Qualities
r.Simplicity = t.Key; r.Simplicity = t.Key;
return r; return r;
}); });
}).AsResponse(); });
} }
private CustomFormatTestResource Test() private CustomFormatTestResource Test()

@ -34,14 +34,14 @@ namespace Radarr.Api.V2.Queue
_pendingReleaseService = pendingReleaseService; _pendingReleaseService = pendingReleaseService;
_downloadService = downloadService; _downloadService = downloadService;
Post[@"/grab/(?<id>[\d]{1,10})"] = x => Grab((int)x.Id); Post(@"/grab/(?<id>[\d]{1,10})", x => Grab((int)x.Id));
Post["/grab/bulk"] = x => Grab(); Post("/grab/bulk", x => Grab());
Delete[@"/(?<id>[\d]{1,10})"] = x => Remove((int)x.Id); Delete(@"/(?<id>[\d]{1,10})", x => Remove((int)x.Id));
Delete["/bulk"] = x => Remove(); Delete("/bulk", x => Remove());
} }
private Response Grab(int id) private object Grab(int id)
{ {
var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id); var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id);
@ -52,10 +52,10 @@ namespace Radarr.Api.V2.Queue
_downloadService.DownloadReport(pendingRelease.RemoteMovie); _downloadService.DownloadReport(pendingRelease.RemoteMovie);
return new object().AsResponse(); return new object();
} }
private Response Grab() private object Grab()
{ {
var resource = Request.Body.FromJson<QueueBulkResource>(); var resource = Request.Body.FromJson<QueueBulkResource>();
@ -71,10 +71,10 @@ namespace Radarr.Api.V2.Queue
_downloadService.DownloadReport(pendingRelease.RemoteMovie); _downloadService.DownloadReport(pendingRelease.RemoteMovie);
} }
return new object().AsResponse(); return new object();
} }
private Response Remove(int id) private object Remove(int id)
{ {
var blacklist = Request.GetBooleanQueryParameter("blacklist"); var blacklist = Request.GetBooleanQueryParameter("blacklist");
@ -85,10 +85,10 @@ namespace Radarr.Api.V2.Queue
_trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId); _trackedDownloadService.StopTracking(trackedDownload.DownloadItem.DownloadId);
} }
return new object().AsResponse(); return new object();
} }
private Response Remove() private object Remove()
{ {
var blacklist = Request.GetBooleanQueryParameter("blacklist"); var blacklist = Request.GetBooleanQueryParameter("blacklist");
@ -107,7 +107,7 @@ namespace Radarr.Api.V2.Queue
_trackedDownloadService.StopTracking(trackedDownloadIds); _trackedDownloadService.StopTracking(trackedDownloadIds);
return new object().AsResponse(); return new object();
} }
private TrackedDownload Remove(int id, bool blacklist) private TrackedDownload Remove(int id, bool blacklist)

@ -1,6 +1,5 @@
using System; using System;
using System.Linq; using System.Linq;
using Nancy.Responses;
using NzbDrone.Common.TPL; using NzbDrone.Common.TPL;
using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.Download.Pending; using NzbDrone.Core.Download.Pending;
@ -8,7 +7,6 @@ using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Queue; using NzbDrone.Core.Queue;
using NzbDrone.SignalR; using NzbDrone.SignalR;
using Radarr.Http; using Radarr.Http;
using Radarr.Http.Extensions;
namespace Radarr.Api.V2.Queue namespace Radarr.Api.V2.Queue
{ {
@ -29,12 +27,12 @@ namespace Radarr.Api.V2.Queue
_broadcastDebounce = new Debouncer(BroadcastChange, TimeSpan.FromSeconds(5)); _broadcastDebounce = new Debouncer(BroadcastChange, TimeSpan.FromSeconds(5));
Get["/"] = x => GetQueueStatusResponse(); Get("/", x => GetQueueStatusResponse());
} }
private JsonResponse<QueueStatusResource> GetQueueStatusResponse() private object GetQueueStatusResponse()
{ {
return GetQueueStatus().AsResponse(); return GetQueueStatus();
} }
private QueueStatusResource GetQueueStatus() private QueueStatusResource GetQueueStatus()

@ -6,9 +6,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="8.4.0" /> <PackageReference Include="FluentValidation" Version="8.4.0" />
<PackageReference Include="Ical.Net" Version="2.2.32" /> <PackageReference Include="Ical.Net" Version="2.2.32" />
<PackageReference Include="Nancy" Version="1.4.4" /> <PackageReference Include="Nancy" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Basic" Version="1.4.1" /> <PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Forms" Version="1.4.1" /> <PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
</ItemGroup> </ItemGroup>

@ -1,8 +1,8 @@
using Nancy; using Radarr.Http;
namespace Radarr.Api.V2 namespace Radarr.Api.V2
{ {
public abstract class RadarrV2FeedModule : NancyModule public abstract class RadarrV2FeedModule : RadarrModule
{ {
protected RadarrV2FeedModule(string resource) protected RadarrV2FeedModule(string resource)
: base("/feed/v2/" + resource.Trim('/')) : base("/feed/v2/" + resource.Trim('/'))

@ -1,8 +1,8 @@
using Nancy; using Radarr.Http;
namespace Radarr.Api.V2 namespace Radarr.Api.V2
{ {
public abstract class RadarrV2Module : NancyModule public abstract class RadarrV2Module : RadarrModule
{ {
protected RadarrV2Module(string resource) protected RadarrV2Module(string resource)
: base("/api/v2/" + resource.Trim('/')) : base("/api/v2/" + resource.Trim('/'))

@ -32,8 +32,8 @@ namespace Radarr.Api.V2.System.Backup
GetResourceAll = GetBackupFiles; GetResourceAll = GetBackupFiles;
DeleteResource = DeleteBackup; DeleteResource = DeleteBackup;
Post[@"/restore/(?<id>[\d]{1,10})"] = x => Restore((int)x.Id); Post(@"/restore/(?<id>[\d]{1,10})", x => Restore((int)x.Id));
Post["/restore/upload"] = x => UploadAndRestore(); Post("/restore/upload", x => UploadAndRestore());
} }
public List<BackupResource> GetBackupFiles() public List<BackupResource> GetBackupFiles()
@ -65,7 +65,7 @@ namespace Radarr.Api.V2.System.Backup
_diskProvider.DeleteFile(path); _diskProvider.DeleteFile(path);
} }
public Response Restore(int id) public object Restore(int id)
{ {
var backup = GetBackup(id); var backup = GetBackup(id);
@ -81,10 +81,10 @@ namespace Radarr.Api.V2.System.Backup
return new return new
{ {
RestartRequired = true RestartRequired = true
}.AsResponse(); };
} }
public Response UploadAndRestore() public object UploadAndRestore()
{ {
var files = Context.Request.Files.ToList(); var files = Context.Request.Files.ToList();
@ -112,7 +112,7 @@ namespace Radarr.Api.V2.System.Backup
return new return new
{ {
RestartRequired = true RestartRequired = true
}.AsResponse(); };
} }
private string GetBackupPath(NzbDrone.Core.Backup.Backup backup) private string GetBackupPath(NzbDrone.Core.Backup.Backup backup)

@ -39,13 +39,13 @@ namespace Radarr.Api.V2.System
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
_database = database; _database = database;
_lifecycleService = lifecycleService; _lifecycleService = lifecycleService;
Get["/status"] = x => GetStatus(); Get("/status", x => GetStatus());
Get["/routes"] = x => GetRoutes(); Get("/routes", x => GetRoutes());
Post["/shutdown"] = x => Shutdown(); Post("/shutdown", x => Shutdown());
Post["/restart"] = x => Restart(); Post("/restart", x => Restart());
} }
private Response GetStatus() private object GetStatus()
{ {
return new return new
{ {
@ -73,24 +73,24 @@ namespace Radarr.Api.V2.System
RuntimeVersion = _platformInfo.Version, RuntimeVersion = _platformInfo.Version,
RuntimeName = PlatformInfo.Platform, RuntimeName = PlatformInfo.Platform,
StartTime = _runtimeInfo.StartTime StartTime = _runtimeInfo.StartTime
}.AsResponse(); };
} }
private Response GetRoutes() private object GetRoutes()
{ {
return _routeCacheProvider.GetCache().Values.AsResponse(); return _routeCacheProvider.GetCache().Values;
} }
private Response Shutdown() private object Shutdown()
{ {
Task.Factory.StartNew(() => _lifecycleService.Shutdown()); Task.Factory.StartNew(() => _lifecycleService.Shutdown());
return new { ShuttingDown = true }.AsResponse(); return new { ShuttingDown = true };
} }
private Response Restart() private object Restart()
{ {
Task.Factory.StartNew(() => _lifecycleService.Restart()); Task.Factory.StartNew(() => _lifecycleService.Restart());
return new { Restarting = true }.AsResponse(); return new { Restarting = true };
} }
} }
} }

@ -1,62 +0,0 @@
using Nancy;
using Nancy.Authentication.Basic;
using Nancy.Authentication.Forms;
using Nancy.Bootstrapper;
using Nancy.Cryptography;
using NzbDrone.Api.Extensions.Pipelines;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Api.Authentication
{
public class EnableAuthInNancy : IRegisterNancyPipeline
{
private readonly IAuthenticationService _authenticationService;
private readonly IConfigService _configService;
private readonly IConfigFileProvider _configFileProvider;
public EnableAuthInNancy(IAuthenticationService authenticationService,
IConfigService configService,
IConfigFileProvider configFileProvider)
{
_authenticationService = authenticationService;
_configService = configService;
_configFileProvider = configFileProvider;
}
public void Register(IPipelines pipelines)
{
RegisterFormsAuth(pipelines);
pipelines.EnableBasicAuthentication(new BasicAuthenticationConfiguration(_authenticationService, "Sonarr"));
pipelines.BeforeRequest.AddItemToEndOfPipeline(RequiresAuthentication);
}
private Response RequiresAuthentication(NancyContext context)
{
Response response = null;
if (!_authenticationService.IsAuthenticated(context))
{
response = new Response { StatusCode = HttpStatusCode.Unauthorized };
}
return response;
}
private void RegisterFormsAuth(IPipelines pipelines)
{
var cryptographyConfiguration = new CryptographyConfiguration(
new RijndaelEncryptionProvider(new PassphraseKeyGenerator(_configService.RijndaelPassphrase,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8})),
new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase,
new byte[] {1, 2, 3, 4, 5, 6, 7, 8}))
);
FormsAuthentication.Enable(pipelines, new FormsAuthenticationConfiguration
{
RedirectUrl = "~/login",
UserMapper = _authenticationService,
CryptographyConfiguration = cryptographyConfiguration
});
}
}
}

@ -3,9 +3,6 @@ using Nancy;
using Nancy.Authentication.Forms; using Nancy.Authentication.Forms;
using Nancy.Extensions; using Nancy.Extensions;
using Nancy.ModelBinding; using Nancy.ModelBinding;
using NLog;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
namespace Radarr.Http.Authentication namespace Radarr.Http.Authentication
@ -19,8 +16,8 @@ namespace Radarr.Http.Authentication
{ {
_authService = authService; _authService = authService;
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
Post["/login"] = x => Login(this.Bind<LoginResource>()); Post("/login", x => Login(this.Bind<LoginResource>()));
Get["/logout"] = x => Logout(); Get("/logout", x => Logout());
} }
private Response Login(LoginResource resource) private Response Login(LoginResource resource)

@ -1,12 +1,12 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using Nancy; using Nancy;
using Nancy.Authentication.Basic; using Nancy.Authentication.Basic;
using Nancy.Authentication.Forms; using Nancy.Authentication.Forms;
using Nancy.Security;
using NLog; using NLog;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Authentication; using NzbDrone.Core.Authentication;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using Radarr.Http.Extensions; using Radarr.Http.Extensions;
@ -26,7 +26,7 @@ namespace Radarr.Http.Authentication
public class AuthenticationService : IAuthenticationService public class AuthenticationService : IAuthenticationService
{ {
private static readonly Logger _authLogger = LogManager.GetLogger("Auth"); private static readonly Logger _authLogger = LogManager.GetLogger("Auth");
private static readonly NzbDroneUser AnonymousUser = new NzbDroneUser { UserName = "Anonymous" }; private const string AnonymousUser = "Anonymous";
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly NancyContext _nancyContext; private readonly NancyContext _nancyContext;
@ -80,15 +80,15 @@ namespace Radarr.Http.Authentication
if (context.CurrentUser != null) if (context.CurrentUser != null)
{ {
LogLogout(context, context.CurrentUser.UserName); LogLogout(context, context.CurrentUser.Identity.Name);
} }
} }
public IUserIdentity Validate(string username, string password) public ClaimsPrincipal Validate(string username, string password)
{ {
if (AUTH_METHOD == AuthenticationType.None) if (AUTH_METHOD == AuthenticationType.None)
{ {
return AnonymousUser; return new ClaimsPrincipal(new GenericIdentity(AnonymousUser));
} }
var user = _userService.FindUser(username, password); var user = _userService.FindUser(username, password);
@ -101,7 +101,7 @@ namespace Radarr.Http.Authentication
LogSuccess(_context, username); LogSuccess(_context, username);
} }
return new NzbDroneUser { UserName = user.Username }; return new ClaimsPrincipal(new GenericIdentity(user.Username));
} }
LogFailure(_context, username); LogFailure(_context, username);
@ -109,18 +109,18 @@ namespace Radarr.Http.Authentication
return null; return null;
} }
public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context) public ClaimsPrincipal GetUserFromIdentifier(Guid identifier, NancyContext context)
{ {
if (AUTH_METHOD == AuthenticationType.None) if (AUTH_METHOD == AuthenticationType.None)
{ {
return AnonymousUser; return new ClaimsPrincipal(new GenericIdentity(AnonymousUser));
} }
var user = _userService.FindUser(identifier); var user = _userService.FindUser(identifier);
if (user != null) if (user != null)
{ {
return new NzbDroneUser { UserName = user.Username }; return new ClaimsPrincipal(new GenericIdentity(user.Username));
} }
LogInvalidated(_context); LogInvalidated(_context);

@ -76,7 +76,7 @@ namespace Radarr.Http.Authentication
FormsAuthentication.FormsAuthenticationCookieName = "RadarrAuth"; FormsAuthentication.FormsAuthenticationCookieName = "RadarrAuth";
var cryptographyConfiguration = new CryptographyConfiguration( var cryptographyConfiguration = new CryptographyConfiguration(
new RijndaelEncryptionProvider(new PassphraseKeyGenerator(_configService.RijndaelPassphrase, Encoding.ASCII.GetBytes(_configService.RijndaelSalt))), new AesEncryptionProvider(new PassphraseKeyGenerator(_configService.RijndaelPassphrase, Encoding.ASCII.GetBytes(_configService.RijndaelSalt))),
new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase, Encoding.ASCII.GetBytes(_configService.HmacSalt))) new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase, Encoding.ASCII.GetBytes(_configService.HmacSalt)))
); );
@ -99,7 +99,7 @@ namespace Radarr.Http.Authentication
context.Response.Headers["Location"].StartsWith($"{_configFileProvider.UrlBase}/login", StringComparison.InvariantCultureIgnoreCase)) || context.Response.Headers["Location"].StartsWith($"{_configFileProvider.UrlBase}/login", StringComparison.InvariantCultureIgnoreCase)) ||
context.Response.StatusCode == HttpStatusCode.Unauthorized) context.Response.StatusCode == HttpStatusCode.Unauthorized)
{ {
context.Response = new { Error = "Unauthorized" }.AsResponse(HttpStatusCode.Unauthorized); context.Response = new { Error = "Unauthorized" }.AsResponse(context, HttpStatusCode.Unauthorized);
} }
} }
} }

@ -1,12 +0,0 @@
using System.Collections.Generic;
using Nancy.Security;
namespace Radarr.Http.Authentication
{
public class NzbDroneUser : IUserIdentity
{
public string UserName { get; set; }
public IEnumerable<string> Claims { get; set; }
}
}

@ -14,7 +14,9 @@ namespace Radarr.Http.ErrorManagement
public void Handle(HttpStatusCode statusCode, NancyContext context) public void Handle(HttpStatusCode statusCode, NancyContext context)
{ {
if (statusCode == HttpStatusCode.SeeOther || statusCode == HttpStatusCode.OK) if (statusCode == HttpStatusCode.SeeOther || statusCode == HttpStatusCode.OK)
{
return; return;
}
if (statusCode == HttpStatusCode.Continue) if (statusCode == HttpStatusCode.Continue)
{ {
@ -23,13 +25,17 @@ namespace Radarr.Http.ErrorManagement
} }
if (statusCode == HttpStatusCode.Unauthorized) if (statusCode == HttpStatusCode.Unauthorized)
{
return; return;
}
if (context.Response.ContentType == "text/html" || context.Response.ContentType == "text/plain") if (context.Response.ContentType == "text/html" || context.Response.ContentType == "text/plain")
{
context.Response = new ErrorModel context.Response = new ErrorModel
{ {
Message = statusCode.ToString() Message = statusCode.ToString()
}.AsResponse(statusCode); }.AsResponse(context, statusCode);
}
} }
} }
} }

@ -27,14 +27,14 @@ namespace Radarr.Http.ErrorManagement
if (exception is ApiException apiException) if (exception is ApiException apiException)
{ {
_logger.Warn(apiException, "API Error"); _logger.Warn(apiException, "API Error");
return apiException.ToErrorResponse(); return apiException.ToErrorResponse(context);
} }
if (exception is ValidationException validationException) if (exception is ValidationException validationException)
{ {
_logger.Warn("Invalid request {0}", validationException.Message); _logger.Warn("Invalid request {0}", validationException.Message);
return validationException.Errors.AsResponse(HttpStatusCode.BadRequest); return validationException.Errors.AsResponse(context, HttpStatusCode.BadRequest);
} }
if (exception is NzbDroneClientException clientException) if (exception is NzbDroneClientException clientException)
@ -43,7 +43,7 @@ namespace Radarr.Http.ErrorManagement
{ {
Message = exception.Message, Message = exception.Message,
Description = exception.ToString() Description = exception.ToString()
}.AsResponse((HttpStatusCode)clientException.StatusCode); }.AsResponse(context, (HttpStatusCode)clientException.StatusCode);
} }
if (exception is ModelNotFoundException notFoundException) if (exception is ModelNotFoundException notFoundException)
@ -52,7 +52,7 @@ namespace Radarr.Http.ErrorManagement
{ {
Message = exception.Message, Message = exception.Message,
Description = exception.ToString() Description = exception.ToString()
}.AsResponse(HttpStatusCode.NotFound); }.AsResponse(context, HttpStatusCode.NotFound);
} }
if (exception is ModelConflictException conflictException) if (exception is ModelConflictException conflictException)
@ -61,7 +61,7 @@ namespace Radarr.Http.ErrorManagement
{ {
Message = exception.Message, Message = exception.Message,
Description = exception.ToString() Description = exception.ToString()
}.AsResponse(HttpStatusCode.Conflict); }.AsResponse(context, HttpStatusCode.Conflict);
} }
if (exception is SQLiteException sqLiteException) if (exception is SQLiteException sqLiteException)
@ -72,7 +72,7 @@ namespace Radarr.Http.ErrorManagement
return new ErrorModel return new ErrorModel
{ {
Message = exception.Message, Message = exception.Message,
}.AsResponse(HttpStatusCode.Conflict); }.AsResponse(context, HttpStatusCode.Conflict);
} }
_logger.Error(sqLiteException, "[{0} {1}]", context.Request.Method, context.Request.Path); _logger.Error(sqLiteException, "[{0} {1}]", context.Request.Method, context.Request.Path);
@ -84,7 +84,7 @@ namespace Radarr.Http.ErrorManagement
{ {
Message = exception.Message, Message = exception.Message,
Description = exception.ToString() Description = exception.ToString()
}.AsResponse(HttpStatusCode.InternalServerError); }.AsResponse(context, HttpStatusCode.InternalServerError);
} }
} }
} }

@ -19,9 +19,9 @@ namespace Radarr.Http.Exceptions
Content = content; Content = content;
} }
public JsonResponse<ErrorModel> ToErrorResponse() public JsonResponse<ErrorModel> ToErrorResponse(NancyContext context)
{ {
return new ErrorModel(this).AsResponse(StatusCode); return new ErrorModel(this).AsResponse(context, StatusCode);
} }
private static string GetMessage(HttpStatusCode statusCode, object content) private static string GetMessage(HttpStatusCode statusCode, object content)

@ -1,18 +1,19 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Nancy; using Nancy;
using Nancy.Responses.Negotiation;
using NzbDrone.Common.Serializer; using NzbDrone.Common.Serializer;
namespace Radarr.Http.Extensions namespace Radarr.Http.Extensions
{ {
public class NancyJsonSerializer : ISerializer public class NancyJsonSerializer : ISerializer
{ {
public bool CanSerialize(string contentType) public bool CanSerialize(MediaRange contentType)
{ {
return true; return contentType == "application/json";
} }
public void Serialize<TModel>(string contentType, TModel model, Stream outputStream) public void Serialize<TModel>(MediaRange contentType, TModel model, Stream outputStream)
{ {
Json.Serialize(model, outputStream); Json.Serialize(model, outputStream);
} }

@ -32,9 +32,9 @@ namespace Radarr.Http.Extensions
return Json.Deserialize(value, type); return Json.Deserialize(value, type);
} }
public static JsonResponse<TModel> AsResponse<TModel>(this TModel model, HttpStatusCode statusCode = HttpStatusCode.OK) public static JsonResponse<TModel> AsResponse<TModel>(this TModel model, NancyContext context, HttpStatusCode statusCode = HttpStatusCode.OK)
{ {
var response = new JsonResponse<TModel>(model, NancySerializer) { StatusCode = statusCode }; var response = new JsonResponse<TModel>(model, NancySerializer, context.Environment) { StatusCode = statusCode };
response.Headers.DisableCache(); response.Headers.DisableCache();
return response; return response;

@ -27,7 +27,7 @@ namespace Radarr.Http.Frontend
_apiKey = configFileProvider.ApiKey; _apiKey = configFileProvider.ApiKey;
_urlBase = configFileProvider.UrlBase; _urlBase = configFileProvider.UrlBase;
Get["/initialize.js"] = x => Index(); Get("/initialize.js", x => Index());
} }
private Response Index() private Response Index()

@ -1,6 +1,5 @@
using System; using System;
using System.IO; using System.IO;
using Nancy;
using NLog; using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;

@ -18,8 +18,8 @@ namespace Radarr.Http.Frontend
_requestMappers = requestMappers; _requestMappers = requestMappers;
_logger = logger; _logger = logger;
Get["/{resource*}"] = x => Index(); Get("/{resource*}", x => Index());
Get["/"] = x => Index(); Get("/", x => Index());
} }
private Response Index() private Response Index()

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using FluentValidation; using FluentValidation;
using Nancy; using Nancy;
using Nancy.Responses.Negotiation;
using Newtonsoft.Json; using Newtonsoft.Json;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using Radarr.Http.Extensions; using Radarr.Http.Extensions;
@ -72,13 +73,13 @@ namespace Radarr.Http.REST
set set
{ {
_deleteResource = value; _deleteResource = value;
Delete[ID_ROUTE] = options => Delete(ID_ROUTE, options =>
{ {
ValidateId(options.Id); ValidateId(options.Id);
DeleteResource((int)options.Id); DeleteResource((int)options.Id);
return new object().AsResponse(); return new object();
}; });
} }
} }
@ -88,7 +89,7 @@ namespace Radarr.Http.REST
set set
{ {
_getResourceById = value; _getResourceById = value;
Get[ID_ROUTE] = options => Get(ID_ROUTE, options =>
{ {
ValidateId(options.Id); ValidateId(options.Id);
try try
@ -100,13 +101,13 @@ namespace Radarr.Http.REST
return new NotFoundResponse(); return new NotFoundResponse();
} }
return resource.AsResponse(); return resource;
} }
catch (ModelNotFoundException) catch (ModelNotFoundException)
{ {
return new NotFoundResponse(); return new NotFoundResponse();
} }
}; });
} }
} }
@ -117,11 +118,11 @@ namespace Radarr.Http.REST
{ {
_getResourceAll = value; _getResourceAll = value;
Get[ROOT_ROUTE] = options => Get(ROOT_ROUTE, options =>
{ {
var resource = GetResourceAll(); var resource = GetResourceAll();
return resource.AsResponse(); return resource;
}; });
} }
} }
@ -132,11 +133,11 @@ namespace Radarr.Http.REST
{ {
_getResourcePaged = value; _getResourcePaged = value;
Get[ROOT_ROUTE] = options => Get(ROOT_ROUTE, options =>
{ {
var resource = GetResourcePaged(ReadPagingResourceFromRequest()); var resource = GetResourcePaged(ReadPagingResourceFromRequest());
return resource.AsResponse(); return resource;
}; });
} }
} }
@ -147,11 +148,11 @@ namespace Radarr.Http.REST
{ {
_getResourceSingle = value; _getResourceSingle = value;
Get[ROOT_ROUTE] = options => Get(ROOT_ROUTE, options =>
{ {
var resource = GetResourceSingle(); var resource = GetResourceSingle();
return resource.AsResponse(); return resource;
}; });
} }
} }
@ -161,12 +162,11 @@ namespace Radarr.Http.REST
set set
{ {
_createResource = value; _createResource = value;
Post[ROOT_ROUTE] = options => Post(ROOT_ROUTE, options =>
{ {
var id = CreateResource(ReadResourceFromRequest()); var id = CreateResource(ReadResourceFromRequest());
return GetResourceById(id).AsResponse(HttpStatusCode.Created); return ResponseWithCode(GetResourceById(id), HttpStatusCode.Created);
}; });
} }
} }
@ -176,23 +176,28 @@ namespace Radarr.Http.REST
set set
{ {
_updateResource = value; _updateResource = value;
Put[ROOT_ROUTE] = options => Put(ROOT_ROUTE, options =>
{ {
var resource = ReadResourceFromRequest(); var resource = ReadResourceFromRequest();
UpdateResource(resource); UpdateResource(resource);
return GetResourceById(resource.Id).AsResponse(HttpStatusCode.Accepted); return ResponseWithCode(GetResourceById(resource.Id), HttpStatusCode.Accepted);
}; });
Put[ID_ROUTE] = options => Put(ID_ROUTE, options =>
{ {
var resource = ReadResourceFromRequest(); var resource = ReadResourceFromRequest();
resource.Id = options.Id; resource.Id = options.Id;
UpdateResource(resource); UpdateResource(resource);
return GetResourceById(resource.Id).AsResponse(HttpStatusCode.Accepted); return ResponseWithCode(GetResourceById(resource.Id), HttpStatusCode.Accepted);
}; });
} }
} }
protected Negotiator ResponseWithCode(object model, HttpStatusCode statusCode)
{
return Negotiate.WithModel(model).WithStatusCode(statusCode);
}
protected TResource ReadResourceFromRequest(bool skipValidate = false) protected TResource ReadResourceFromRequest(bool skipValidate = false)
{ {
TResource resource; TResource resource;

@ -5,9 +5,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentValidation" Version="8.4.0" /> <PackageReference Include="FluentValidation" Version="8.4.0" />
<PackageReference Include="Nancy" Version="1.4.4" /> <PackageReference Include="Nancy" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Basic" Version="1.4.1" /> <PackageReference Include="Nancy.Authentication.Basic" Version="2.0.0" />
<PackageReference Include="Nancy.Authentication.Forms" Version="1.4.1" /> <PackageReference Include="Nancy.Authentication.Forms" Version="2.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="NLog" Version="4.6.7" /> <PackageReference Include="NLog" Version="4.6.7" />
</ItemGroup> </ItemGroup>

@ -1,12 +1,13 @@
using System;
using System.Linq; using System.Linq;
using Nancy;
using Nancy.Bootstrapper; using Nancy.Bootstrapper;
using Nancy.Diagnostics; using Nancy.Diagnostics;
using Nancy.Responses.Negotiation;
using NLog; using NLog;
using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation; using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Lifecycle;
using NzbDrone.Core.Messaging.Events;
using Radarr.Http.Extensions.Pipelines; using Radarr.Http.Extensions.Pipelines;
using TinyIoC; using TinyIoC;
@ -51,7 +52,19 @@ namespace Radarr.Http
return _tinyIoCContainer; return _tinyIoCContainer;
} }
protected override DiagnosticsConfiguration DiagnosticsConfiguration => new DiagnosticsConfiguration { Password = @"password" }; protected override Func<ITypeCatalog, NancyInternalConfiguration> InternalConfiguration
{
get
{
// We don't support Xml Serialization atm
return NancyInternalConfiguration.WithOverrides(x => x.ResponseProcessors.Remove(typeof(XmlProcessor)));
}
}
public override void Configure(Nancy.Configuration.INancyEnvironment environment)
{
environment.Diagnostics(password: @"password");
}
protected override byte[] FavIcon => null; protected override byte[] FavIcon => null;
} }

@ -0,0 +1,18 @@
using Nancy;
using Nancy.Responses.Negotiation;
namespace Radarr.Http
{
public abstract class RadarrModule : NancyModule
{
protected RadarrModule(string resource)
: base(resource)
{
}
protected Negotiator ResponseWithCode(object model, HttpStatusCode statusCode)
{
return Negotiate.WithModel(model).WithStatusCode(statusCode);
}
}
}

@ -6,6 +6,7 @@ using System.Reflection;
using Nancy; using Nancy;
using Nancy.Diagnostics; using Nancy.Diagnostics;
using Nancy.Bootstrapper; using Nancy.Bootstrapper;
using Nancy.Configuration;
namespace Radarr.Http namespace Radarr.Http
{ {
@ -52,6 +53,47 @@ namespace Radarr.Http
return this.ApplicationContainer.Resolve<INancyEngine>(); return this.ApplicationContainer.Resolve<INancyEngine>();
} }
//
// Summary:
// Gets the Nancy.Configuration.INancyEnvironmentConfigurator used by th.
//
// Returns:
// An Nancy.Configuration.INancyEnvironmentConfigurator instance.
protected override INancyEnvironmentConfigurator GetEnvironmentConfigurator()
{
return this.ApplicationContainer.Resolve<INancyEnvironmentConfigurator>();
}
//
// Summary:
// Get the Nancy.Configuration.INancyEnvironment instance.
//
// Returns:
// An configured Nancy.Configuration.INancyEnvironment instance.
//
// Remarks:
// The boostrapper must be initialised (Nancy.Bootstrapper.INancyBootstrapper.Initialise)
// prior to calling this.
public override INancyEnvironment GetEnvironment()
{
return this.ApplicationContainer.Resolve<INancyEnvironment>();
}
//
// Summary:
// Registers an Nancy.Configuration.INancyEnvironment instance in the container.
//
// Parameters:
// container:
// The container to register into.
//
// environment:
// The Nancy.Configuration.INancyEnvironment instance to register.
protected override void RegisterNancyEnvironment(TinyIoCContainer container, INancyEnvironment environment)
{
ApplicationContainer.Register<INancyEnvironment>(environment);
}
/// <summary> /// <summary>
/// Create a default, unconfigured, container /// Create a default, unconfigured, container
/// </summary> /// </summary>

Loading…
Cancel
Save