diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index 4eee11c67..372117541 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -85,8 +85,6 @@ namespace PlexRequests.UI //container.Register(); - - container.Register(); base.ConfigureRequestContainer(container, context); } @@ -100,6 +98,7 @@ namespace PlexRequests.UI StaticConfiguration.DisableErrorTraces = false; + base.ApplicationStartup(container, pipelines); // Enable forms auth diff --git a/PlexRequests.UI/Helpers/ValidationHelper.cs b/PlexRequests.UI/Helpers/ValidationHelper.cs new file mode 100644 index 000000000..ff50a6b95 --- /dev/null +++ b/PlexRequests.UI/Helpers/ValidationHelper.cs @@ -0,0 +1,59 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: ValidationHelper.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 System.Linq; + +using Nancy.Validation; + + +using PlexRequests.UI.Models; + +namespace PlexRequests.UI.Helpers +{ + public static class ValidationHelper + { + + /// + /// This will send the first error as a JsonResponseModel + /// + /// The result. + /// + public static JsonResponseModel SendJsonError(this ModelValidationResult result) + { + var errors = result.Errors; + return errors + .Select(e => e.Value.FirstOrDefault()) + .Where(modelValidationError => modelValidationError != null) + .Select(modelValidationError => + new JsonResponseModel + { + Result = false, + Message = modelValidationError.ErrorMessage + }) + .FirstOrDefault(); + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index 70c7e5fb0..3be996745 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -31,7 +31,7 @@ using Nancy; using Nancy.Extensions; using Nancy.ModelBinding; using Nancy.Responses.Negotiation; -using Nancy.Security; +using Nancy.Validation; using NLog; @@ -39,6 +39,7 @@ using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels; using PlexRequests.Helpers; +using PlexRequests.UI.Helpers; using PlexRequests.UI.Models; namespace PlexRequests.UI.Modules @@ -214,9 +215,16 @@ namespace PlexRequests.UI.Modules private Response SaveCouchPotato() { var couchPotatoSettings = this.Bind(); - CpService.SaveSettings(couchPotatoSettings); + var valid = this.Validate(couchPotatoSettings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } - return Context.GetRedirect("~/admin/couchpotato"); + var result = CpService.SaveSettings(couchPotatoSettings); + return Response.AsJson(result + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for CouchPotato!" } + : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } private Negotiator Plex() @@ -229,9 +237,18 @@ namespace PlexRequests.UI.Modules private Response SavePlex() { var plexSettings = this.Bind(); - PlexService.SaveSettings(plexSettings); + var valid = this.Validate(plexSettings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } + - return Context.GetRedirect("~/admin/plex"); + var result = PlexService.SaveSettings(plexSettings); + + return Response.AsJson(result + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Plex!" } + : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } private Negotiator Sonarr() @@ -243,10 +260,19 @@ namespace PlexRequests.UI.Modules private Response SaveSonarr() { - var plexSettings = this.Bind(); - SonarrService.SaveSettings(plexSettings); + var sonarrSettings = this.Bind(); + + var valid = this.Validate(sonarrSettings); + if (!valid.IsValid) + { + return Response.AsJson(valid.SendJsonError()); + } + + var result = SonarrService.SaveSettings(sonarrSettings); - return Response.AsJson(new JsonResponseModel { Result = true }); + return Response.AsJson(result + ? new JsonResponseModel { Result = true, Message = "Successfully Updated the Settings for Sonarr!" } + : new JsonResponseModel { Result = false, Message = "Could not update the settings, take a look at the logs." }); } private Response GetSonarrQualityProfiles() diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index 430232605..35a8c8bbc 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -65,6 +65,10 @@ ..\packages\FluentScheduler.3.1.46\lib\net40\FluentScheduler.dll True + + ..\packages\FluentValidation.6.2.1.0\lib\Net45\FluentValidation.dll + True + ..\packages\Humanizer.Core.2.0.1\lib\dotnet\Humanizer.dll True @@ -109,6 +113,10 @@ ..\packages\Nancy.Owin.1.4.1\lib\net40\Nancy.Owin.dll True + + ..\packages\Nancy.Validation.FluentValidation.1.4.1\lib\net40\Nancy.Validation.FluentValidation.dll + True + ..\packages\Nancy.Viewengines.Razor.1.4.1\lib\net40\Nancy.ViewEngines.Razor.dll True @@ -152,6 +160,10 @@ + + + + PreserveNewest diff --git a/PlexRequests.UI/Validators/CouchPotatoValidator.cs b/PlexRequests.UI/Validators/CouchPotatoValidator.cs new file mode 100644 index 000000000..5f7c7ef2e --- /dev/null +++ b/PlexRequests.UI/Validators/CouchPotatoValidator.cs @@ -0,0 +1,42 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrValidator.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.Core.SettingModels; + +namespace PlexRequests.UI.Validators +{ + public class CouchPotatoValidator : AbstractValidator + { + public CouchPotatoValidator() + { + RuleFor(request => request.Ip).NotEmpty().WithMessage("You must specify a IP/Host name."); + RuleFor(request => request.Port).NotEmpty().WithMessage("You must specify a Port."); + RuleFor(request => request.ApiKey).NotEmpty().WithMessage("You must specify a Api Key."); + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Validators/PlexValidator.cs b/PlexRequests.UI/Validators/PlexValidator.cs new file mode 100644 index 000000000..a686b1b62 --- /dev/null +++ b/PlexRequests.UI/Validators/PlexValidator.cs @@ -0,0 +1,41 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrValidator.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.Core.SettingModels; + +namespace PlexRequests.UI.Validators +{ + public class PlexValidator : AbstractValidator + { + public PlexValidator() + { + RuleFor(request => request.Ip).NotEmpty().WithMessage("You must specify a IP/Host name."); + RuleFor(request => request.Port).NotEmpty().WithMessage("You must specify a Port."); + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Validators/SonarrValidator.cs b/PlexRequests.UI/Validators/SonarrValidator.cs new file mode 100644 index 000000000..e35eb654b --- /dev/null +++ b/PlexRequests.UI/Validators/SonarrValidator.cs @@ -0,0 +1,44 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: SonarrValidator.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.Core.SettingModels; + +namespace PlexRequests.UI.Validators +{ + public class SonarrValidator : AbstractValidator + { + public SonarrValidator() + { + RuleFor(request => request.ApiKey).NotEmpty().WithMessage("You must specify a Api Key."); + RuleFor(request => request.Ip).NotEmpty().WithMessage("You must specify a IP/Host name."); + RuleFor(request => request.Port).NotEmpty().WithMessage("You must specify a Port."); + RuleFor(request => request.QualityProfile).NotEmpty().WithMessage("You must specify a Quality Profile."); + RuleFor(request => request.RootPath).NotEmpty().WithMessage("You must specify a Root Path."); + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/CouchPotato.cshtml b/PlexRequests.UI/Views/Admin/CouchPotato.cshtml index b20787ced..986355e1f 100644 --- a/PlexRequests.UI/Views/Admin/CouchPotato.cshtml +++ b/PlexRequests.UI/Views/Admin/CouchPotato.cshtml @@ -50,7 +50,7 @@
- +
@@ -85,6 +85,33 @@ } }); }); + + $('#save').click(function (e) { + e.preventDefault(); + var port = $('#portNumber').val(); + if (isNaN(port)) { + generateNotify("You must specify a Port.", "warning"); + return; + } + var $form = $("#mainForm"); + $.ajax({ + type: $form.prop("method"), + data: $form.serialize(), + url: $form.prop("action"), + dataType: "json", + success: function (response) { + if (response.result === true) { + generateNotify(response.message, "success"); + } else { + generateNotify(response.message, "warning"); + } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + } + }); + }); }); \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/Plex.cshtml b/PlexRequests.UI/Views/Admin/Plex.cshtml index 3e8632bb8..2a1d59054 100644 --- a/PlexRequests.UI/Views/Admin/Plex.cshtml +++ b/PlexRequests.UI/Views/Admin/Plex.cshtml @@ -37,7 +37,7 @@
- +
@@ -72,5 +72,33 @@ }); }); + $('#save').click(function (e) { + e.preventDefault(); + var port = $('#portNumber').val(); + if (isNaN(port)) { + generateNotify("You must specify a Port.", "warning"); + return; + } + + var $form = $("#mainForm"); + $.ajax({ + type: $form.prop("method"), + data: $form.serialize(), + url: $form.prop("action"), + dataType: "json", + success: function (response) { + if (response.result === true) { + generateNotify(response.message, "success"); + } else { + generateNotify(response.message, "warning"); + } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + } + }); + }); + }); \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/Settings.cshtml b/PlexRequests.UI/Views/Admin/Settings.cshtml index 3b6d594f7..06c6b95a9 100644 --- a/PlexRequests.UI/Views/Admin/Settings.cshtml +++ b/PlexRequests.UI/Views/Admin/Settings.cshtml @@ -75,7 +75,7 @@ - //TODO: Need to implement this*@ + //TODO: Need to implement this*@
@@ -86,4 +86,5 @@ - \ No newline at end of file + + diff --git a/PlexRequests.UI/Views/Admin/Sonarr.cshtml b/PlexRequests.UI/Views/Admin/Sonarr.cshtml index b85a55e24..e7c6cccf0 100644 --- a/PlexRequests.UI/Views/Admin/Sonarr.cshtml +++ b/PlexRequests.UI/Views/Admin/Sonarr.cshtml @@ -131,6 +131,11 @@ $('#save').click(function(e) { e.preventDefault(); + var port = $('#portNumber').val(); + if (isNaN(port)) { + generateNotify("You must specify a Port.", "warning"); + return; + } var qualityProfile = $("#profiles option:selected").val(); var $form = $("#mainForm"); diff --git a/PlexRequests.UI/packages.config b/PlexRequests.UI/packages.config index cc8667954..f1e5e48fc 100644 --- a/PlexRequests.UI/packages.config +++ b/PlexRequests.UI/packages.config @@ -2,6 +2,7 @@ + @@ -13,6 +14,7 @@ +