From 187a59261ab056dd969670f9a206e20dfa121bf4 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 19 May 2016 14:29:41 +0100 Subject: [PATCH] More work on the api and documentation #222 #205 --- PlexRequests.UI.Tests/ApiModuleTests.cs | 84 +++++++++++++++++++ .../PlexRequests.UI.Tests.csproj | 1 + .../RequestedModelDataProvider.cs | 4 + PlexRequests.UI/Modules/ApiMetadataModule.cs | 16 +++- PlexRequests.UI/Modules/ApiModule.cs | 54 ++++++++---- PlexRequests.UI/PlexRequests.UI.csproj | 1 + .../Validators/RequestedModelValidator.cs | 45 ++++++++++ 7 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 PlexRequests.UI.Tests/ApiModuleTests.cs create mode 100644 PlexRequests.UI/Validators/RequestedModelValidator.cs diff --git a/PlexRequests.UI.Tests/ApiModuleTests.cs b/PlexRequests.UI.Tests/ApiModuleTests.cs new file mode 100644 index 000000000..7208b8bfb --- /dev/null +++ b/PlexRequests.UI.Tests/ApiModuleTests.cs @@ -0,0 +1,84 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: ApiModuleTests.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +using Moq; + +using Nancy; +using Nancy.Testing; + +using NUnit.Framework; + +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.UI.Helpers; +using PlexRequests.UI.Modules; + +namespace PlexRequests.UI.Tests +{ + [TestFixture] + [Ignore("Locator :(")] + public class ApiModuleTests + { + private ConfigurableBootstrapper Bootstrapper { get; set; } + + [SetUp] + public void Setup() + { + var requestMock = new Mock(); + var settingsMock = new Mock>(); + Bootstrapper = new ConfigurableBootstrapper(with => + { + with.Module(); + with.Dependency(requestMock.Object); + with.Dependency(settingsMock.Object); + with.ApplicationStartup( + (c, a) => + { + var loc = ServiceLocator.Instance; + loc.SetContainer(c); + }); + }); + + } + + [Test] + public void GetAllRequests() + { + + var browser = new Browser(Bootstrapper); + + var result = browser.Post("/api/requests", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.Query("apikey","a"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj b/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj index 21deb5eff..3c7db1543 100644 --- a/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj +++ b/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj @@ -90,6 +90,7 @@ + diff --git a/PlexRequests.UI/ModelDataProviders/RequestedModelDataProvider.cs b/PlexRequests.UI/ModelDataProviders/RequestedModelDataProvider.cs index a838416c2..fe75957d8 100644 --- a/PlexRequests.UI/ModelDataProviders/RequestedModelDataProvider.cs +++ b/PlexRequests.UI/ModelDataProviders/RequestedModelDataProvider.cs @@ -34,6 +34,10 @@ namespace PlexRequests.UI.ModelDataProviders { public class RequestedModelDataProvider : ISwaggerModelDataProvider { + /// + /// Gets the model data for the api documentation. + /// + /// public SwaggerModelData GetModelData() { return SwaggerModelData.ForType(with => diff --git a/PlexRequests.UI/Modules/ApiMetadataModule.cs b/PlexRequests.UI/Modules/ApiMetadataModule.cs index 18e764621..eb8ae6a52 100644 --- a/PlexRequests.UI/Modules/ApiMetadataModule.cs +++ b/PlexRequests.UI/Modules/ApiMetadataModule.cs @@ -42,11 +42,23 @@ namespace PlexRequests.UI.Modules with.ResourcePath("/requests"); with.Summary("The list of requests"); - with.Notes("This returns a list of users from our awesome app"); + with.Notes("This returns a list of requests"); with.QueryParam("apikey", "The Api Key found in the settings", true); with.Model>>(); }); + Describe["GetRequest"] = description => description.AsSwagger(with => + { + with.ResourcePath("/requests/{id}"); + with.Summary("Get's a single request"); + + with.Notes("This returns a single request"); + with.QueryParam("apikey", "The Api Key found in the settings", true); + //with.QueryParam("id", "The request id to return", true); + with.PathParam("id"); + with.Model>>(); + }); + Describe["PostRequests"] = description => description.AsSwagger(with => { with.ResourcePath("/requests"); @@ -72,7 +84,7 @@ namespace PlexRequests.UI.Modules with.ResourcePath("/requests"); with.Summary("Deletes an existing request"); with.Model>(); - with.BodyParam("The request", true); + with.BodyParam("The request ID to delete", true); with.QueryParam("apikey", "The Api Key found in the settings", true); with.Notes("Deletes an existing request. If the request doesn't exist we will return an error."); }); diff --git a/PlexRequests.UI/Modules/ApiModule.cs b/PlexRequests.UI/Modules/ApiModule.cs index 3b0e7b40f..eb4f34f84 100644 --- a/PlexRequests.UI/Modules/ApiModule.cs +++ b/PlexRequests.UI/Modules/ApiModule.cs @@ -29,8 +29,6 @@ using System.Collections.Generic; using Nancy; using Nancy.ModelBinding; -using Nancy.Responses.Negotiation; -using Nancy.Validation; using PlexRequests.Core; using PlexRequests.Store; @@ -42,6 +40,7 @@ namespace PlexRequests.UI.Modules public ApiModule(IRequestService service) : base("api") { Get["GetRequests","/requests"] = x => GetRequests(); + Get["GetRequest","/requests/{id}"] = x => GetSingleRequests(x); Post["PostRequests", "/requests"] = x => CreateRequest(); Put["PutRequests", "/requests"] = x => UpdateRequest(); Delete["DeleteRequests", "/requests"] = x => DeleteRequest(); @@ -61,15 +60,33 @@ namespace PlexRequests.UI.Modules return ReturnReponse(apiModel); } + public Response GetSingleRequests(dynamic x) + { + var id = (int)x.id; + var apiModel = new ApiModel> { Data = new List() }; + + var requests = RequestService.Get(id); + if (string.IsNullOrEmpty(requests.Title)) + { + apiModel.Error = true; + apiModel.ErrorMessage = "Request does not exist"; + return ReturnReponse(apiModel); + } + apiModel.Data.Add(requests); + + return ReturnReponse(apiModel); + } + public Response CreateRequest() { - var request = this.Bind(); - var valid = this.Validate(request); - if (!valid.IsValid) + var request = this.BindAndValidate(); + + if (!ModelValidationResult.IsValid) { - return ReturnValidationReponse(valid); + return ReturnValidationReponse(ModelValidationResult); } + var apiModel = new ApiModel(); var result = RequestService.AddRequest(request); @@ -87,11 +104,11 @@ namespace PlexRequests.UI.Modules public Response UpdateRequest() { - var request = this.Bind(); - var valid = this.Validate(request); - if (!valid.IsValid) + var request = this.BindAndValidate(); + + if (!ModelValidationResult.IsValid) { - return ReturnValidationReponse(valid); + return ReturnValidationReponse(ModelValidationResult); } @@ -112,17 +129,20 @@ namespace PlexRequests.UI.Modules public Response DeleteRequest() { - var request = this.Bind(); - var valid = this.Validate(request); - if (!valid.IsValid) - { - return ReturnValidationReponse(valid); - } + var id = this.Bind(); + var apiModel = new ApiModel(); try { - RequestService.DeleteRequest(request); + var exisitingRequest = RequestService.Get(id); + if (exisitingRequest == null) + { + apiModel.Error = true; + apiModel.ErrorMessage = $"The request id {id} does not exist"; + return ReturnReponse(apiModel); + } + RequestService.DeleteRequest(exisitingRequest); apiModel.Data = true; return ReturnReponse(apiModel); diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index a2609cb6b..e74ce7fc1 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -185,6 +185,7 @@ + diff --git a/PlexRequests.UI/Validators/RequestedModelValidator.cs b/PlexRequests.UI/Validators/RequestedModelValidator.cs new file mode 100644 index 000000000..1f6f1d171 --- /dev/null +++ b/PlexRequests.UI/Validators/RequestedModelValidator.cs @@ -0,0 +1,45 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: RequestedModelValidator.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +using FluentValidation; + +using PlexRequests.Store; + +namespace PlexRequests.UI.Validators +{ + public class RequestedModelValidator : AbstractValidator + { + public RequestedModelValidator() + { + RuleFor(x => x.Title).NotNull(); + RuleFor(x => x.ProviderId).NotNull().WithMessage("'ProviderId' must not be empty. Please use either TVMaze Id or TheMovieDb Id"); + RuleFor(x => x.PosterPath).NotNull(); + RuleFor(x => x.ReleaseDate).NotNull(); + RuleFor(x => x.Type).NotNull(); + RuleFor(x => x.RequestedUsers).NotNull(); + } + } +} \ No newline at end of file