From e33ee794d2967e4880dc75fe472347f11a169d28 Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 1 Jun 2016 13:07:53 +0100 Subject: [PATCH 01/46] Create .gitattributes --- .gitattributes | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..210f21789 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,71 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain + + +PlexRequests.UI/Content/* linguist-vendored +PlexRequests.UI/Content/* linguist-vendored +base.scss linguist-vendored=false +requests-1.7.js linguist-vendored=false +search-1.7.js linguist-vendored=false +site-1.7.js linguist-vendored=false From db846f2fbb04ba2b63e89c12e1a2949b35a42868 Mon Sep 17 00:00:00 2001 From: Jamie Date: Sat, 4 Jun 2016 12:02:22 +0100 Subject: [PATCH 02/46] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 521df81d6..8387f7c54 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# Plex Requests .NET! +![PR](http://i.imgur.com/s4nswSA.png?1) +____ [![Gitter](https://badges.gitter.im/tidusjar/PlexRequest.NET.svg)](https://gitter.im/tidusjar/PlexRequests.Net?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build status](https://ci.appveyor.com/api/projects/status/hgj8j6lcea7j0yhn?svg=true)](https://ci.appveyor.com/project/tidusjar/requestplex) [![Linux Status](https://travis-ci.org/tidusjar/PlexRequests.Net.svg)](https://travis-ci.org/tidusjar/PlexRequests.Net) From e50e406a28b0a6ec10d0538a74de0b33b87fd014 Mon Sep 17 00:00:00 2001 From: Jamie Date: Fri, 10 Jun 2016 11:48:35 +0100 Subject: [PATCH 03/46] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8387f7c54..3028c2db5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -![PR](http://i.imgur.com/s4nswSA.png?1) +![](http://i.imgur.com/s4nswSA.png?1) ____ [![Gitter](https://badges.gitter.im/tidusjar/PlexRequest.NET.svg)](https://gitter.im/tidusjar/PlexRequests.Net?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build status](https://ci.appveyor.com/api/projects/status/hgj8j6lcea7j0yhn?svg=true)](https://ci.appveyor.com/project/tidusjar/requestplex) @@ -30,9 +30,8 @@ I wanted to write a similar application in .Net! ![Preview](http://i.imgur.com/DgwkIsW.gif) #Installation -Download the latest [Release](https://github.com/tidusjar/PlexRequests.Net/releases). -Extract the .zip file (Unblock if on Windows! Right Click > Properties > Unblock). -Just run `PlexRequests.exe`! (Mono compatible `mono PlexRequests.exe`) + +[Windows Guide!](http://www.htpcguides.com/install-plex-requests-net-windows-system-service/) # FAQ Do you have an issue or a question? if so check out our [FAQ!](https://github.com/tidusjar/PlexRequests.Net/wiki/FAQ) From 9ec7fa0ef6db9c3c260d7943a234fa8ef28b326a Mon Sep 17 00:00:00 2001 From: Jamie Date: Thu, 16 Jun 2016 11:14:14 +0100 Subject: [PATCH 04/46] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3028c2db5..08f5873e4 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ I wanted to write a similar application in .Net! #Installation [Windows Guide!](http://www.htpcguides.com/install-plex-requests-net-windows-system-service/) +[Ubuntu Guide!](http://www.htpcguides.com/install-plex-requests-net-ubuntu-14-x/) # FAQ Do you have an issue or a question? if so check out our [FAQ!](https://github.com/tidusjar/PlexRequests.Net/wiki/FAQ) From f30bc103ed9242e41ffabe5936251b350ae43b3d Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 21 Jun 2016 09:01:48 +0100 Subject: [PATCH 05/46] revert branch to 664dae2 --- PlexRequests.UI.Tests/IssuesModuleTests.cs | 149 ------------------ .../PlexRequests.UI.Tests.csproj | 1 - PlexRequests.UI/Bootstrapper.cs | 51 +++--- PlexRequests.UI/Helpers/ContainerHelper.cs | 48 ------ PlexRequests.UI/Modules/IssuesModule.cs | 2 - PlexRequests.UI/PlexRequests.UI.csproj | 1 - 6 files changed, 25 insertions(+), 227 deletions(-) delete mode 100644 PlexRequests.UI.Tests/IssuesModuleTests.cs delete mode 100644 PlexRequests.UI/Helpers/ContainerHelper.cs diff --git a/PlexRequests.UI.Tests/IssuesModuleTests.cs b/PlexRequests.UI.Tests/IssuesModuleTests.cs deleted file mode 100644 index 411cebbf2..000000000 --- a/PlexRequests.UI.Tests/IssuesModuleTests.cs +++ /dev/null @@ -1,149 +0,0 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: IssuesModuleTests.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.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -using Moq; - -using Nancy; -using Nancy.Testing; - -using Newtonsoft.Json; - -using NUnit.Framework; - -using PlexRequests.Core; -using PlexRequests.Core.Models; -using PlexRequests.Core.SettingModels; -using PlexRequests.Helpers; -using PlexRequests.Services.Interfaces; -using PlexRequests.UI.Models; -using PlexRequests.UI.Modules; - -using Ploeh.AutoFixture; - -namespace PlexRequests.UI.Tests -{ - [TestFixture] - public class IssuesModuleTests - { - [SetUp] - public void Setup() - { - var f = new Fixture(); - ModelList = f.CreateMany(); - PlexRequestMock = new Mock>(); - PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); - PlexRequestMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(new PlexRequestSettings())); - IssueServiceMock = new Mock(); - RequestServiceMock = new Mock(); - NotificationServiceMock = new Mock(); - IssueServiceMock.Setup(x => x.GetAllAsync()).Returns(Task.FromResult(ModelList)); - - Bootstrapper = new ConfigurableBootstrapper( - with => - { - with.Module(); - with.Dependency(PlexRequestMock.Object); - with.Dependency(IssueServiceMock.Object); - with.Dependency(RequestServiceMock.Object); - with.Dependency(NotificationServiceMock.Object); - with.RootPathProvider(); - }); - - Bootstrapper.WithSession(new Dictionary { { SessionKeys.UsernameKey, "abc" } }); - } - - private Mock> PlexRequestMock { get; set; } - private Mock IssueServiceMock { get; set; } - private Mock RequestServiceMock { get; set; } - private Mock NotificationServiceMock { get; set; } - private ConfigurableBootstrapper Bootstrapper { get; set; } - private IEnumerable ModelList { get; set; } - - private IEnumerable NonResolvedModel => ModelList.Where(x => x.IssueStatus != IssueStatus.ResolvedIssue); - - [Test] - public void GetIssuesNonAdminButAllCanSee() - { - var browser = new Browser(Bootstrapper); - var result = browser.Get( - "/issues/pending", - with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); - - var body = JsonConvert.DeserializeObject>(result.Body.AsString()); - - Assert.That(body.Count, Is.EqualTo(NonResolvedModel.Count())); - Assert.That(body[0].Title, Is.Not.Empty); - } - - [Test] - public void GetIssuesForAdmin() - { - Bootstrapper = new ConfigurableBootstrapper( - with => - { - with.Module(); - with.Dependency(PlexRequestMock.Object); - with.Dependency(IssueServiceMock.Object); - with.Dependency(RequestServiceMock.Object); - with.Dependency(NotificationServiceMock.Object); - with.RootPathProvider(); - with.RequestStartup( - (container, pipelines, context) => - { - context.CurrentUser = new UserIdentity() { Claims = new[] { UserClaims.Admin } }; - }); - }); - - Bootstrapper.WithSession(new Dictionary { { SessionKeys.UsernameKey, "abc" } }); - var browser = new Browser(Bootstrapper); - var result = browser.Get( - "/issues/pending", - with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); - - var body = JsonConvert.DeserializeObject>(result.Body.AsString()); - Assert.That(body.Count, Is.EqualTo(NonResolvedModel.Count())); - Assert.That(body[0].Title, Is.Not.Empty); - } - } -} \ 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 95ac4be3a..5ec37a74a 100644 --- a/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj +++ b/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj @@ -105,7 +105,6 @@ - diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index a43f4c8f6..176404b02 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -43,6 +43,7 @@ using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels; using PlexRequests.Helpers; +using PlexRequests.Services; using PlexRequests.Services.Interfaces; using PlexRequests.Services.Notification; using PlexRequests.Store; @@ -146,7 +147,7 @@ namespace PlexRequests.UI notificationService.Subscribe(new SlackNotification(container.Resolve(), slackService)); } } - + protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context) { //CORS Enable @@ -167,33 +168,31 @@ namespace PlexRequests.UI container.Register, UserRepository>(); container.Register(); container.Register(); - - // Settings - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - container.RegisterSetting(); - - // Repository - container.RegisterRepo(); - container.RegisterRepo(); - container.RegisterRepo(); - container.RegisterRepo(); - + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); // Notification Service container.Register().AsSingleton(); - + // Settings + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + + // Repo's + container.Register, GenericRepository>(); + container.Register, GenericRepository>(); + container.Register, GenericRepository>(); + container.Register, GenericRepository>(); container.Register(); container.Register(); container.Register(); @@ -210,7 +209,7 @@ namespace PlexRequests.UI container.Register(); container.Register(); - + // Api container.Register(); container.Register(); diff --git a/PlexRequests.UI/Helpers/ContainerHelper.cs b/PlexRequests.UI/Helpers/ContainerHelper.cs deleted file mode 100644 index 85c4f7f92..000000000 --- a/PlexRequests.UI/Helpers/ContainerHelper.cs +++ /dev/null @@ -1,48 +0,0 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: ContainerHelper.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 Nancy.TinyIoc; - -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.Store; -using PlexRequests.Store.Repository; - -namespace PlexRequests.UI.Helpers -{ - public static class ContainerHelper - { - public static void RegisterSetting(this TinyIoCContainer container) where T : Settings, new() - { - container.Register, SettingsServiceV2>(); - } - - public static void RegisterRepo(this TinyIoCContainer container) where T : Entity, new() - { - container.Register, GenericRepository>(); - } - } -} \ No newline at end of file diff --git a/PlexRequests.UI/Modules/IssuesModule.cs b/PlexRequests.UI/Modules/IssuesModule.cs index 9e10ac156..82cb1d2f0 100644 --- a/PlexRequests.UI/Modules/IssuesModule.cs +++ b/PlexRequests.UI/Modules/IssuesModule.cs @@ -317,8 +317,6 @@ namespace PlexRequests.UI.Modules /// Filters the issues. Checks to see if we have set UsersCanViewOnlyOwnIssues in the database and filters upon the user logged in and that setting. /// /// The issues. - /// if set to true [show resolved]. - /// private async Task> FilterIssuesAsync(IEnumerable issues, bool showResolved = false) { var settings = await PlexRequestSettings.GetSettingsAsync(); diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index 75290e3d1..99b5f8641 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -159,7 +159,6 @@ - From 5a1b606f01512db21c5cb01102b45514741d81eb Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 21 Jun 2016 13:02:53 +0100 Subject: [PATCH 06/46] Set the defaults for the landing page --- PlexRequests.UI/Modules/AdminModule.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index daf5f0967..0cdebf427 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -818,7 +818,14 @@ namespace PlexRequests.UI.Modules private async Task LandingPage() { var settings = await LandingSettings.GetSettingsAsync(); - + if (settings.NoticeEnd == DateTime.MinValue) + { + settings.NoticeEnd = DateTime.Now; + } + if (settings.NoticeStart == DateTime.MinValue) + { + settings.NoticeStart = DateTime.Now; + } return View["LandingPage", settings]; } From 6f18c69f5f743464f8706cb8aa1ad46d468b7cef Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 21 Jun 2016 13:39:23 +0100 Subject: [PATCH 07/46] Fixes to the issues --- PlexRequests.Core/Setup.cs | 3 ++- PlexRequests.UI/Modules/IssuesModule.cs | 6 +++--- PlexRequests.UI/Views/Issues/Index.cshtml | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/PlexRequests.Core/Setup.cs b/PlexRequests.Core/Setup.cs index 2c015f55c..33682d7b3 100644 --- a/PlexRequests.Core/Setup.cs +++ b/PlexRequests.Core/Setup.cs @@ -105,7 +105,8 @@ namespace PlexRequests.Core SearchForMovies = true, SearchForTvShows = true, WeeklyRequestLimit = 0, - BaseUrl = baseUrl ?? string.Empty + BaseUrl = baseUrl ?? string.Empty, + CollectAnalyticData = true, }; var s = new SettingsServiceV2(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); s.SaveSettings(defaultSettings); diff --git a/PlexRequests.UI/Modules/IssuesModule.cs b/PlexRequests.UI/Modules/IssuesModule.cs index 82cb1d2f0..1c66831e0 100644 --- a/PlexRequests.UI/Modules/IssuesModule.cs +++ b/PlexRequests.UI/Modules/IssuesModule.cs @@ -362,7 +362,7 @@ namespace PlexRequests.UI.Modules return myIssues; } - private async Task RemoveIssue(int issueId) + private async Task RemoveIssue(int issueId) { try { @@ -378,13 +378,13 @@ namespace PlexRequests.UI.Modules await IssuesService.DeleteIssueAsync(issueId); } - return View["Index"]; + return Response.AsJson(new JsonResponseModel() { Result = true }); } catch (Exception e) { Log.Error(e); - return View["Index"]; + return Response.AsJson(new JsonResponseModel() { Result = false, Message = "Could not delete issue! Check the logs."}); } } diff --git a/PlexRequests.UI/Views/Issues/Index.cshtml b/PlexRequests.UI/Views/Issues/Index.cshtml index 2c18ccf41..77d7b983f 100644 --- a/PlexRequests.UI/Views/Issues/Index.cshtml +++ b/PlexRequests.UI/Views/Issues/Index.cshtml @@ -61,7 +61,7 @@ \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 6771fa74b..cfef4c77b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,26 +1,26 @@ -version: 1.8.{build} -configuration: Release -assembly_info: - patch: true - file: '**\AssemblyInfo.*' - assembly_version: '1.8.1' - assembly_file_version: '{version}' - assembly_informational_version: '1.8.1' -before_build: -- cmd: appveyor-retry nuget restore -build: - verbosity: minimal -after_build: -- cmd: >- - 7z a PlexRequests.zip %APPVEYOR_BUILD_FOLDER%\PlexRequests.UI\bin\Release\ - - appveyor PushArtifact PlexRequests.zip - -deploy: -- provider: GitHub - release: PlexRequests v$(appveyor_build_version) - auth_token: - secure: jDpp1/WUQl3uN41fNI3VeZoRZbDiDfs3GPQ1v+C5ZNE3cWdnUvuJfCCfUbYUV1Rp - draft: true - on: - branch: master +version: 1.8.{build} +configuration: Release +assembly_info: + patch: true + file: '**\AssemblyInfo.*' + assembly_version: '1.8.1' + assembly_file_version: '{version}' + assembly_informational_version: '1.8.1' +before_build: +- cmd: appveyor-retry nuget restore +build: + verbosity: minimal +after_build: +- cmd: >- + 7z a PlexRequests.zip %APPVEYOR_BUILD_FOLDER%\PlexRequests.UI\bin\Release\ + + appveyor PushArtifact PlexRequests.zip + +deploy: +- provider: GitHub + release: PlexRequests v$(appveyor_build_version) + auth_token: + secure: jDpp1/WUQl3uN41fNI3VeZoRZbDiDfs3GPQ1v+C5ZNE3cWdnUvuJfCCfUbYUV1Rp + draft: true + on: + branch: master From f76e54408eca5d4249db438b1d132082e21a1f70 Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Tue, 21 Jun 2016 20:20:44 -0500 Subject: [PATCH 13/46] show request type in notifications #346 and fix an issue from previous commit for #345 --- .../Notification/EmailMessageNotification.cs | 5 +- .../Notification/NotificationModel.cs | 80 ++--- .../Notification/PushbulletNotification.cs | 283 +++++++++--------- .../Notification/PushoverNotification.cs | 277 ++++++++--------- PlexRequests.Store/RequestedModel.cs | 198 ++++++------ PlexRequests.UI/Modules/SearchModule.cs | 43 +-- 6 files changed, 458 insertions(+), 428 deletions(-) diff --git a/PlexRequests.Services/Notification/EmailMessageNotification.cs b/PlexRequests.Services/Notification/EmailMessageNotification.cs index 080091504..466ff7a24 100644 --- a/PlexRequests.Services/Notification/EmailMessageNotification.cs +++ b/PlexRequests.Services/Notification/EmailMessageNotification.cs @@ -36,6 +36,7 @@ using PlexRequests.Core; using PlexRequests.Core.SettingModels; using PlexRequests.Services.Interfaces; using SmtpClient = MailKit.Net.Smtp.SmtpClient; +using PlexRequests.Store; namespace PlexRequests.Services.Notification { @@ -119,8 +120,8 @@ namespace PlexRequests.Services.Notification { var message = new MimeMessage { - Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has requested {model.Title}! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}" }, - Subject = $"Plex Requests: New request for {model.Title}!" + Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has requested the {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}" }, + Subject = $"Plex Requests: New {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} request for {model.Title}!" }; message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); message.To.Add(new MailboxAddress(settings.RecipientEmail, settings.RecipientEmail)); diff --git a/PlexRequests.Services/Notification/NotificationModel.cs b/PlexRequests.Services/Notification/NotificationModel.cs index 2cc4e7fdb..e74f90dd4 100644 --- a/PlexRequests.Services/Notification/NotificationModel.cs +++ b/PlexRequests.Services/Notification/NotificationModel.cs @@ -1,40 +1,42 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: NotificationModel.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; - -namespace PlexRequests.Services.Notification -{ - public class NotificationModel - { - public string Title { get; set; } - public string Body { get; set; } - public DateTime DateTime { get; set; } - public NotificationType NotificationType { get; set; } - public string User { get; set; } - public string UserEmail { get; set; } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: NotificationModel.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 PlexRequests.Store; +using System; + +namespace PlexRequests.Services.Notification +{ + public class NotificationModel + { + public string Title { get; set; } + public string Body { get; set; } + public DateTime DateTime { get; set; } + public NotificationType NotificationType { get; set; } + public string User { get; set; } + public string UserEmail { get; set; } + public RequestType RequestType { get; set; } + } } \ No newline at end of file diff --git a/PlexRequests.Services/Notification/PushbulletNotification.cs b/PlexRequests.Services/Notification/PushbulletNotification.cs index 70f318331..8eda8d0b9 100644 --- a/PlexRequests.Services/Notification/PushbulletNotification.cs +++ b/PlexRequests.Services/Notification/PushbulletNotification.cs @@ -1,142 +1,143 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: PushbulletNotification.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; -using System.Threading.Tasks; - -using NLog; - -using PlexRequests.Api.Interfaces; -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.Services.Interfaces; - -namespace PlexRequests.Services.Notification -{ - public class PushbulletNotification : INotification - { - public PushbulletNotification(IPushbulletApi pushbulletApi, ISettingsService settings) - { - PushbulletApi = pushbulletApi; - SettingsService = settings; - } - private IPushbulletApi PushbulletApi { get; } - private ISettingsService SettingsService { get; } - - private static Logger Log = LogManager.GetCurrentClassLogger(); - public string NotificationName => "PushbulletNotification"; - public async Task NotifyAsync(NotificationModel model) - { - var configuration = GetSettings(); - await NotifyAsync(model, configuration); - } - - public async Task NotifyAsync(NotificationModel model, Settings settings) - { - if (settings == null) await NotifyAsync(model); - - var pushSettings = (PushbulletNotificationSettings)settings; - - if (!ValidateConfiguration(pushSettings)) return; - - switch (model.NotificationType) - { - case NotificationType.NewRequest: - await PushNewRequestAsync(model, pushSettings); - break; - case NotificationType.Issue: - await PushIssueAsync(model, pushSettings); - break; - case NotificationType.RequestAvailable: - break; - case NotificationType.RequestApproved: - break; - case NotificationType.AdminNote: - break; - case NotificationType.Test: - await PushTestAsync(pushSettings); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - private bool ValidateConfiguration(PushbulletNotificationSettings settings) - { - if (!settings.Enabled) - { - return false; - } - if (string.IsNullOrEmpty(settings.AccessToken)) - { - return false; - } - return true; - } - - private PushbulletNotificationSettings GetSettings() - { - return SettingsService.GetSettings(); - } - - private async Task PushNewRequestAsync(NotificationModel model, PushbulletNotificationSettings settings) - { - var message = $"{model.Title} has been requested by user: {model.User}"; - var pushTitle = $"Plex Requests: {model.Title} has been requested!"; - await Push(settings, message, pushTitle); - } - - private async Task PushIssueAsync(NotificationModel model, PushbulletNotificationSettings settings) - { - var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; - var pushTitle = $"Plex Requests: A new issue has been reported for {model.Title}"; - await Push(settings, message, pushTitle); - } - - private async Task PushTestAsync(PushbulletNotificationSettings settings) - { - var message = "This is just a test! Success!"; - var pushTitle = "Plex Requests: Test Message!"; - await Push(settings, message, pushTitle); - } - - private async Task Push(PushbulletNotificationSettings settings, string message, string title) - { - try - { - var result = await PushbulletApi.PushAsync(settings.AccessToken, title, message, settings.DeviceIdentifier); - if (result != null) - { - Log.Error("Pushbullet api returned a null value, the notification did not get pushed"); - } - } - catch (Exception e) - { - Log.Error(e); - } - } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: PushbulletNotification.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; +using System.Threading.Tasks; + +using NLog; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; +using PlexRequests.Store; + +namespace PlexRequests.Services.Notification +{ + public class PushbulletNotification : INotification + { + public PushbulletNotification(IPushbulletApi pushbulletApi, ISettingsService settings) + { + PushbulletApi = pushbulletApi; + SettingsService = settings; + } + private IPushbulletApi PushbulletApi { get; } + private ISettingsService SettingsService { get; } + + private static Logger Log = LogManager.GetCurrentClassLogger(); + public string NotificationName => "PushbulletNotification"; + public async Task NotifyAsync(NotificationModel model) + { + var configuration = GetSettings(); + await NotifyAsync(model, configuration); + } + + public async Task NotifyAsync(NotificationModel model, Settings settings) + { + if (settings == null) await NotifyAsync(model); + + var pushSettings = (PushbulletNotificationSettings)settings; + + if (!ValidateConfiguration(pushSettings)) return; + + switch (model.NotificationType) + { + case NotificationType.NewRequest: + await PushNewRequestAsync(model, pushSettings); + break; + case NotificationType.Issue: + await PushIssueAsync(model, pushSettings); + break; + case NotificationType.RequestAvailable: + break; + case NotificationType.RequestApproved: + break; + case NotificationType.AdminNote: + break; + case NotificationType.Test: + await PushTestAsync(pushSettings); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private bool ValidateConfiguration(PushbulletNotificationSettings settings) + { + if (!settings.Enabled) + { + return false; + } + if (string.IsNullOrEmpty(settings.AccessToken)) + { + return false; + } + return true; + } + + private PushbulletNotificationSettings GetSettings() + { + return SettingsService.GetSettings(); + } + + private async Task PushNewRequestAsync(NotificationModel model, PushbulletNotificationSettings settings) + { + var message = $"The {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} '{model.Title}' has been requested by user: {model.User}"; + var pushTitle = $"Plex Requests: The {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} {model.Title} has been requested!"; + await Push(settings, message, pushTitle); + } + + private async Task PushIssueAsync(NotificationModel model, PushbulletNotificationSettings settings) + { + var message = $"A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; + var pushTitle = $"Plex Requests: A new issue has been reported for {model.Title}"; + await Push(settings, message, pushTitle); + } + + private async Task PushTestAsync(PushbulletNotificationSettings settings) + { + var message = "This is just a test! Success!"; + var pushTitle = "Plex Requests: Test Message!"; + await Push(settings, message, pushTitle); + } + + private async Task Push(PushbulletNotificationSettings settings, string message, string title) + { + try + { + var result = await PushbulletApi.PushAsync(settings.AccessToken, title, message, settings.DeviceIdentifier); + if (result != null) + { + Log.Error("Pushbullet api returned a null value, the notification did not get pushed"); + } + } + catch (Exception e) + { + Log.Error(e); + } + } + } } \ No newline at end of file diff --git a/PlexRequests.Services/Notification/PushoverNotification.cs b/PlexRequests.Services/Notification/PushoverNotification.cs index d39492563..9831e6562 100644 --- a/PlexRequests.Services/Notification/PushoverNotification.cs +++ b/PlexRequests.Services/Notification/PushoverNotification.cs @@ -1,139 +1,140 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: PushbulletNotification.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; -using System.Threading.Tasks; - -using NLog; - -using PlexRequests.Api.Interfaces; -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.Services.Interfaces; - -namespace PlexRequests.Services.Notification -{ - public class PushoverNotification : INotification - { - public PushoverNotification(IPushoverApi pushoverApi, ISettingsService settings) - { - PushoverApi = pushoverApi; - SettingsService = settings; - } - private IPushoverApi PushoverApi { get; } - private ISettingsService SettingsService { get; } - - private static Logger Log = LogManager.GetCurrentClassLogger(); - public string NotificationName => "PushoverNotification"; - public async Task NotifyAsync(NotificationModel model) - { - var configuration = GetSettings(); - await NotifyAsync(model, configuration); - } - - public async Task NotifyAsync(NotificationModel model, Settings settings) - { - if (settings == null) await NotifyAsync(model); - - var pushSettings = (PushoverNotificationSettings)settings; - - if (!ValidateConfiguration(pushSettings)) return; - - switch (model.NotificationType) - { - case NotificationType.NewRequest: - await PushNewRequestAsync(model, pushSettings); - break; - case NotificationType.Issue: - await PushIssueAsync(model, pushSettings); - break; - case NotificationType.RequestAvailable: - break; - case NotificationType.RequestApproved: - break; - case NotificationType.AdminNote: - break; - case NotificationType.Test: - await PushTestAsync(model, pushSettings); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - private bool ValidateConfiguration(PushoverNotificationSettings settings) - { - if (!settings.Enabled) - { - return false; - } - if (string.IsNullOrEmpty(settings.AccessToken) || string.IsNullOrEmpty(settings.UserToken)) - { - return false; - } - return true; - } - - private PushoverNotificationSettings GetSettings() - { - return SettingsService.GetSettings(); - } - - private async Task PushNewRequestAsync(NotificationModel model, PushoverNotificationSettings settings) - { - var message = $"Plex Requests: {model.Title} has been requested by user: {model.User}"; - await Push(settings, message); - } - - private async Task PushIssueAsync(NotificationModel model, PushoverNotificationSettings settings) - { - var message = $"Plex Requests: A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; - await Push(settings, message); - } - - private async Task PushTestAsync(NotificationModel model, PushoverNotificationSettings settings) - { - var message = $"Plex Requests: Test Message!"; - await Push(settings, message); - } - - private async Task Push(PushoverNotificationSettings settings, string message) - { - try - { - var result = await PushoverApi.PushAsync(settings.AccessToken, message, settings.UserToken); - if (result?.status != 1) - { - Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed"); - } - } - catch (Exception e) - { - Log.Error(e); - } - } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: PushbulletNotification.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; +using System.Threading.Tasks; + +using NLog; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; +using PlexRequests.Store; + +namespace PlexRequests.Services.Notification +{ + public class PushoverNotification : INotification + { + public PushoverNotification(IPushoverApi pushoverApi, ISettingsService settings) + { + PushoverApi = pushoverApi; + SettingsService = settings; + } + private IPushoverApi PushoverApi { get; } + private ISettingsService SettingsService { get; } + + private static Logger Log = LogManager.GetCurrentClassLogger(); + public string NotificationName => "PushoverNotification"; + public async Task NotifyAsync(NotificationModel model) + { + var configuration = GetSettings(); + await NotifyAsync(model, configuration); + } + + public async Task NotifyAsync(NotificationModel model, Settings settings) + { + if (settings == null) await NotifyAsync(model); + + var pushSettings = (PushoverNotificationSettings)settings; + + if (!ValidateConfiguration(pushSettings)) return; + + switch (model.NotificationType) + { + case NotificationType.NewRequest: + await PushNewRequestAsync(model, pushSettings); + break; + case NotificationType.Issue: + await PushIssueAsync(model, pushSettings); + break; + case NotificationType.RequestAvailable: + break; + case NotificationType.RequestApproved: + break; + case NotificationType.AdminNote: + break; + case NotificationType.Test: + await PushTestAsync(model, pushSettings); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private bool ValidateConfiguration(PushoverNotificationSettings settings) + { + if (!settings.Enabled) + { + return false; + } + if (string.IsNullOrEmpty(settings.AccessToken) || string.IsNullOrEmpty(settings.UserToken)) + { + return false; + } + return true; + } + + private PushoverNotificationSettings GetSettings() + { + return SettingsService.GetSettings(); + } + + private async Task PushNewRequestAsync(NotificationModel model, PushoverNotificationSettings settings) + { + var message = $"Plex Requests: The {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} '{model.Title}' has been requested by user: {model.User}"; + await Push(settings, message); + } + + private async Task PushIssueAsync(NotificationModel model, PushoverNotificationSettings settings) + { + var message = $"Plex Requests: A new issue: {model.Body} has been reported by user: {model.User} for the title: {model.Title}"; + await Push(settings, message); + } + + private async Task PushTestAsync(NotificationModel model, PushoverNotificationSettings settings) + { + var message = $"Plex Requests: Test Message!"; + await Push(settings, message); + } + + private async Task Push(PushoverNotificationSettings settings, string message) + { + try + { + var result = await PushoverApi.PushAsync(settings.AccessToken, message, settings.UserToken); + if (result?.status != 1) + { + Log.Error("Pushover api returned a status that was not 1, the notification did not get pushed"); + } + } + catch (Exception e) + { + Log.Error(e); + } + } + } } \ No newline at end of file diff --git a/PlexRequests.Store/RequestedModel.cs b/PlexRequests.Store/RequestedModel.cs index c63ede547..254b4f7be 100644 --- a/PlexRequests.Store/RequestedModel.cs +++ b/PlexRequests.Store/RequestedModel.cs @@ -1,90 +1,108 @@ -using System; -using Dapper.Contrib.Extensions; -using System.Collections.Generic; -using System.Linq; -using Newtonsoft.Json; - -namespace PlexRequests.Store -{ - [Table("Requested")] - public class RequestedModel : Entity - { - public RequestedModel() - { - RequestedUsers = new List(); - } - - // ReSharper disable once IdentifierTypo - public int ProviderId { get; set; } - public string ImdbId { get; set; } - public string TvDbId { get; set; } - public string Overview { get; set; } - public string Title { get; set; } - public string PosterPath { get; set; } - public DateTime ReleaseDate { get; set; } - public RequestType Type { get; set; } - public string Status { get; set; } - public bool Approved { get; set; } - - [Obsolete("Use RequestedUsers")] - public string RequestedBy { get; set; } - - public DateTime RequestedDate { get; set; } - public bool Available { get; set; } - public IssueState Issues { get; set; } - public string OtherMessage { get; set; } - public string AdminNote { get; set; } - public int[] SeasonList { get; set; } - public int SeasonCount { get; set; } - public string SeasonsRequested { get; set; } - public string MusicBrainzId { get; set; } - public List RequestedUsers { get; set; } - public string ArtistName { get; set; } - public string ArtistId { get; set; } - public int IssueId { get; set; } - - [JsonIgnore] - public List AllUsers - { - get - { - var u = new List(); - if (!string.IsNullOrEmpty(RequestedBy)) - { - u.Add(RequestedBy); - } - - if (RequestedUsers.Any()) - { - u.AddRange(RequestedUsers.Where(requestedUser => requestedUser != RequestedBy)); - } - return u; - } - } - - [JsonIgnore] - public bool CanApprove => !Approved && !Available; - - public bool UserHasRequested(string username) - { - return AllUsers.Any(x => x.Equals(username, StringComparison.OrdinalIgnoreCase)); - } - } - - public enum RequestType - { - Movie, - TvShow, - Album - } - - public enum IssueState - { - None = 99, - WrongAudio = 0, - NoSubtitles = 1, - WrongContent = 2, - PlaybackIssues = 3, - Other = 4, // Provide a message - } -} +using System; +using Dapper.Contrib.Extensions; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; + +namespace PlexRequests.Store +{ + [Table("Requested")] + public class RequestedModel : Entity + { + public RequestedModel() + { + RequestedUsers = new List(); + } + + // ReSharper disable once IdentifierTypo + public int ProviderId { get; set; } + public string ImdbId { get; set; } + public string TvDbId { get; set; } + public string Overview { get; set; } + public string Title { get; set; } + public string PosterPath { get; set; } + public DateTime ReleaseDate { get; set; } + public RequestType Type { get; set; } + public string Status { get; set; } + public bool Approved { get; set; } + + [Obsolete("Use RequestedUsers")] + public string RequestedBy { get; set; } + + public DateTime RequestedDate { get; set; } + public bool Available { get; set; } + public IssueState Issues { get; set; } + public string OtherMessage { get; set; } + public string AdminNote { get; set; } + public int[] SeasonList { get; set; } + public int SeasonCount { get; set; } + public string SeasonsRequested { get; set; } + public string MusicBrainzId { get; set; } + public List RequestedUsers { get; set; } + public string ArtistName { get; set; } + public string ArtistId { get; set; } + public int IssueId { get; set; } + + [JsonIgnore] + public List AllUsers + { + get + { + var u = new List(); + if (!string.IsNullOrEmpty(RequestedBy)) + { + u.Add(RequestedBy); + } + + if (RequestedUsers.Any()) + { + u.AddRange(RequestedUsers.Where(requestedUser => requestedUser != RequestedBy)); + } + return u; + } + } + + [JsonIgnore] + public bool CanApprove => !Approved && !Available; + + public bool UserHasRequested(string username) + { + return AllUsers.Any(x => x.Equals(username, StringComparison.OrdinalIgnoreCase)); + } + } + + public enum RequestType + { + Movie, + TvShow, + Album + } + + public static class RequestTypeDisplay + { + public static string Get(RequestType type) + { + switch (type) + { + case RequestType.Movie: + return "Movie"; + case RequestType.TvShow: + return "TV Show"; + case RequestType.Album: + return "Album"; + default: + return string.Empty; + } + } + } + + public enum IssueState + { + None = 99, + WrongAudio = 0, + NoSubtitles = 1, + WrongContent = 2, + PlaybackIssues = 3, + Other = 4, // Provide a message + } +} diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index e42ae0739..f02a417ea 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -488,14 +488,15 @@ namespace PlexRequests.UI.Modules Log.Info("Adding movie to database (No approval required)"); await RequestService.AddRequestAsync(model); - if (ShouldSendNotification(settings)) + if (ShouldSendNotification(RequestType.Movie, settings)) { var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, - NotificationType = NotificationType.NewRequest + NotificationType = NotificationType.NewRequest, + RequestType = RequestType.Movie }; await NotificationService.Publish(notificationModel); } @@ -515,14 +516,15 @@ namespace PlexRequests.UI.Modules Log.Info("Adding movie to database (No approval required)"); await RequestService.AddRequestAsync(model); - if (ShouldSendNotification(settings)) + if (ShouldSendNotification(RequestType.Movie, settings)) { var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, - NotificationType = NotificationType.NewRequest + NotificationType = NotificationType.NewRequest, + RequestType = RequestType.Movie }; await NotificationService.Publish(notificationModel); } @@ -536,7 +538,7 @@ namespace PlexRequests.UI.Modules Log.Info("Adding movie to database"); var id = await RequestService.AddRequestAsync(model); - var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; + var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest, RequestType = RequestType.Movie }; await NotificationService.Publish(notificationModel); return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullMovieName} was successfully added!" }); @@ -663,14 +665,15 @@ namespace PlexRequests.UI.Modules Log.Debug("Adding tv to database requests (No approval required & Sonarr)"); await RequestService.AddRequestAsync(model); - if (ShouldSendNotification(settings)) + if (ShouldSendNotification(RequestType.TvShow, settings)) { var notify1 = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, - NotificationType = NotificationType.NewRequest + NotificationType = NotificationType.NewRequest, + RequestType = RequestType.TvShow }; await NotificationService.Publish(notify1); } @@ -691,14 +694,15 @@ namespace PlexRequests.UI.Modules model.Approved = true; Log.Debug("Adding tv to database requests (No approval required & SickRage)"); await RequestService.AddRequestAsync(model); - if (ShouldSendNotification(settings)) + if (ShouldSendNotification(RequestType.TvShow, settings)) { var notify2 = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, - NotificationType = NotificationType.NewRequest + NotificationType = NotificationType.NewRequest, + RequestType = RequestType.TvShow }; await NotificationService.Publish(notify2); } @@ -713,14 +717,15 @@ namespace PlexRequests.UI.Modules model.Approved = true; Log.Debug("Adding tv to database requests (No approval required) and Sonarr/Sickrage not setup"); await RequestService.AddRequestAsync(model); - if (ShouldSendNotification(settings)) + if (ShouldSendNotification(RequestType.TvShow, settings)) { var notify2 = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, - NotificationType = NotificationType.NewRequest + NotificationType = NotificationType.NewRequest, + RequestType = RequestType.TvShow }; await NotificationService.Publish(notify2); } @@ -733,15 +738,15 @@ namespace PlexRequests.UI.Modules await RequestService.AddRequestAsync(model); - var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest }; + var notificationModel = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, NotificationType = NotificationType.NewRequest, RequestType = RequestType.TvShow }; await NotificationService.Publish(notificationModel); return Response.AsJson(new JsonResponseModel { Result = true, Message = $"{fullShowName} was successfully added!" }); } - private bool ShouldSendNotification(PlexRequestSettings prSettings) + private bool ShouldSendNotification(RequestType type, PlexRequestSettings prSettings) { - var sendNotification = !prSettings.IgnoreNotifyForAutoApprovedRequests; + var sendNotification = ShouldAutoApprove(type, prSettings) ? !prSettings.IgnoreNotifyForAutoApprovedRequests : true; var claims = Context.CurrentUser?.Claims; if (claims != null) { @@ -838,14 +843,15 @@ namespace PlexRequests.UI.Modules model.Approved = true; await RequestService.AddRequestAsync(model); - if (ShouldSendNotification(settings)) + if (ShouldSendNotification(RequestType.Album, settings)) { var notify2 = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, - NotificationType = NotificationType.NewRequest + NotificationType = NotificationType.NewRequest, + RequestType = RequestType.Album }; await NotificationService.Publish(notify2); } @@ -858,14 +864,15 @@ namespace PlexRequests.UI.Modules }); } - if (ShouldSendNotification(settings)) + if (ShouldSendNotification(RequestType.Album, settings)) { var notify2 = new NotificationModel { Title = model.Title, User = Username, DateTime = DateTime.Now, - NotificationType = NotificationType.NewRequest + NotificationType = NotificationType.NewRequest, + RequestType = RequestType.Album }; await NotificationService.Publish(notify2); } From ffc0ec34c40c48c7859414c24fb5b498736fc1d3 Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Tue, 21 Jun 2016 21:11:36 -0500 Subject: [PATCH 14/46] null provider check for movies --- PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs b/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs index 253ba7af3..68b8da01b 100644 --- a/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs +++ b/PlexRequests.Services/Jobs/PlexAvailabilityChecker.cs @@ -179,7 +179,8 @@ namespace PlexRequests.Services.Jobs { if (advanced) { - if (movie.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase)) + if (!string.IsNullOrEmpty(movie.ProviderId) && + movie.ProviderId.Equals(providerId, StringComparison.InvariantCultureIgnoreCase)) { return true; } From 7b57e3fffc8d6c41e9e1ff5fa5bd898ee29c00f5 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 09:33:20 +0100 Subject: [PATCH 15/46] Fixed #353 #354 #355 --- PlexRequests.Core/Setup.cs | 4 - PlexRequests.UI/Content/issue-details.js | 40 +- PlexRequests.UI/Modules/IssuesModule.cs | 18 +- PlexRequests.UI/Views/Issues/Details.cshtml | 2 +- PlexRequests.UI/Views/Landing/Index.cshtml | 11 +- PlexRequests.UI/Views/Requests/Index.cshtml | 787 ++++++++++---------- 6 files changed, 433 insertions(+), 429 deletions(-) diff --git a/PlexRequests.Core/Setup.cs b/PlexRequests.Core/Setup.cs index 85a72d7f9..e66a15cec 100644 --- a/PlexRequests.Core/Setup.cs +++ b/PlexRequests.Core/Setup.cs @@ -57,10 +57,6 @@ namespace PlexRequests.Core var version = CheckSchema(); if (version > 0) { - if (version > 1700 && version <= 1799) - { - MigrateToVersion1700(); - } if (version > 1799 && version <= 1800) { MigrateToVersion1800(); diff --git a/PlexRequests.UI/Content/issue-details.js b/PlexRequests.UI/Content/issue-details.js index 28b10c997..92693ac94 100644 --- a/PlexRequests.UI/Content/issue-details.js +++ b/PlexRequests.UI/Content/issue-details.js @@ -27,19 +27,43 @@ $(".theNoteSaveButton").click(function (e) { }); }); // Update the note modal -$('#noteModal').on('show.bs.modal', function (event) { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = button.data('identifier'); // Extract info from data-* attributes +$('#noteModal').on('show.bs.modal', function (event) { + var button = $(event.relatedTarget); // Button that triggered the modal + var id = button.data('identifier'); // Extract info from data-* attributes + var issue = button.data('issue'); - var modal = $(this); - modal.find('.theNoteSaveButton').val(id); // Add ID to the button - var requestField = modal.find('.noteId'); - requestField.val(id); // Add ID to the hidden field + var modal = $(this); + modal.find('.theNoteSaveButton').val(id); // Add ID to the button + var requestField = modal.find('.noteId'); + requestField.val(id); // Add ID to the hidden field + var noteType = modal.find('.issue'); + noteType.val(issue); + }); - + + + $('.delete').click(function(e) { + e.preventDefault(); + var url = createBaseUrl(base, "/issues"); + var $form = $("#removeForm"); + + $.ajax({ + type: $form.prop("method"), + url: $form.prop("action"), + data: $form.serialize(), + dataType: "json", + success: function (response) { + if (checkJsonResponse(response)) { window.location.replace(url); } + }, + error: function (e) { + console.log(e); + generateNotify("Something went wrong!", "danger"); + } + }); + }); diff --git a/PlexRequests.UI/Modules/IssuesModule.cs b/PlexRequests.UI/Modules/IssuesModule.cs index 1c66831e0..d5129f303 100644 --- a/PlexRequests.UI/Modules/IssuesModule.cs +++ b/PlexRequests.UI/Modules/IssuesModule.cs @@ -48,7 +48,7 @@ namespace PlexRequests.UI.Modules Get["/issuecount", true] = async (x, ct) => await IssueCount(); Get["/tabCount", true] = async (x, ct) => await TabCount(); - Post["/issuecomment", true] = async (x, ct) => await ReportRequestIssue((int)Request.Form.provierId, IssueState.Other, (string)Request.Form.commentArea); + Post["/issuecomment", true] = async (x, ct) => await ReportRequestIssue((int)Request.Form.providerId, IssueState.Other, (string)Request.Form.commentArea); Post["/nonrequestissue", true] = async (x, ct) => await ReportNonRequestIssue((int)Request.Form.providerId, (string)Request.Form.type, (IssueState)(int)Request.Form.issue, null); @@ -369,16 +369,22 @@ namespace PlexRequests.UI.Modules this.RequiresClaims(UserClaims.Admin); var issue = await IssuesService.GetAsync(issueId); var request = await RequestService.GetAsync(issue.RequestId); + if (request.Id > 0) + { + request.IssueId = 0; // No issue; - request.IssueId = 0; // No issue; - - var result = await RequestService.UpdateRequestAsync(request); - if (result) + var result = await RequestService.UpdateRequestAsync(request); + if (result) + { + await IssuesService.DeleteIssueAsync(issueId); + } + } + else { await IssuesService.DeleteIssueAsync(issueId); } - return Response.AsJson(new JsonResponseModel() { Result = true }); + return Response.AsJson(new JsonResponseModel { Result = true }); } catch (Exception e) diff --git a/PlexRequests.UI/Views/Issues/Details.cshtml b/PlexRequests.UI/Views/Issues/Details.cshtml index 53a6c8994..4c4f06178 100644 --- a/PlexRequests.UI/Views/Issues/Details.cshtml +++ b/PlexRequests.UI/Views/Issues/Details.cshtml @@ -42,7 +42,7 @@ } @if (Model.IssueStatus == IssueStatus.ResolvedIssue) { -
+
diff --git a/PlexRequests.UI/Views/Landing/Index.cshtml b/PlexRequests.UI/Views/Landing/Index.cshtml index 8e0cd90a0..2a3ff8945 100644 --- a/PlexRequests.UI/Views/Landing/Index.cshtml +++ b/PlexRequests.UI/Views/Landing/Index.cshtml @@ -1,8 +1,15 @@  @using PlexRequests.UI.Helpers @inherits PlexRequests.UI.Helpers.EmptyViewBase - - +@{ + var baseUrl = Html.GetBaseUrl(); + var formAction = string.Empty; + if (!string.IsNullOrEmpty(baseUrl.ToHtmlString())) + { + formAction = "/" + baseUrl.ToHtmlString(); + } +} +
@if (Model.NoticeEnable && (!Model.EnabledNoticeTime || Model.NoticeActive)) { diff --git a/PlexRequests.UI/Views/Requests/Index.cshtml b/PlexRequests.UI/Views/Requests/Index.cshtml index 95db35a11..e0e36f5ed 100644 --- a/PlexRequests.UI/Views/Requests/Index.cshtml +++ b/PlexRequests.UI/Views/Requests/Index.cshtml @@ -1,408 +1,379 @@ -@using Nancy.Security -@using PlexRequests.UI.Helpers -@{ - var baseUrl = Html.GetBaseUrl(); - var formAction = string.Empty; - if (!string.IsNullOrEmpty(baseUrl.ToHtmlString())) - { - formAction = "/" + baseUrl.ToHtmlString(); - } -} -
-

Requests

-

Below you can see yours and all other requests, as well as their download and approval status.

-
- - - -
- - -
-
-
-
-
- @if (Context.CurrentUser.IsAuthenticated()) //TODO replace with IsAdmin - { - @if (Model.SearchForMovies) - { - - - } - @if (Model.SearchForTvShows) - { - - - } - @if (Model.SearchForMusic) - { - - - } - } -
- - -
-
-
- @if (Model.SearchForMovies) - { - - -
- -
-
- -
-
-
- } - - @if (Model.SearchForTvShows) - { - -
- -
-
- -
-
-
- } - - @if (Model.SearchForMusic) - { - -
- -
-
- -
-
-
- } -
- -
- - - - - - - - - - -@Html.LoadRequestAssets() - - +@using Nancy.Security +@using PlexRequests.UI.Helpers +@{ + var baseUrl = Html.GetBaseUrl(); + var formAction = string.Empty; + if (!string.IsNullOrEmpty(baseUrl.ToHtmlString())) + { + formAction = "/" + baseUrl.ToHtmlString(); + } +} +
+

Requests

+

Below you can see yours and all other requests, as well as their download and approval status.

+
+ + + +
+ + +
+
+
+
+
+ @if (Context.CurrentUser.IsAuthenticated()) //TODO replace with IsAdmin + { + @if (Model.SearchForMovies) + { + + + } + @if (Model.SearchForTvShows) + { + + + } + @if (Model.SearchForMusic) + { + + + } + } +
+ + +
+
+
+ @if (Model.SearchForMovies) + { + + +
+ +
+
+ +
+
+
+ } + + @if (Model.SearchForTvShows) + { + +
+ +
+
+ +
+
+
+ } + + @if (Model.SearchForMusic) + { + +
+ +
+
+ +
+
+
+ } +
+ +
+ + + + + + + + +@Html.LoadRequestAssets() + + From 63e0d0e531fb0511c18e8a5d20696e7d00232eca Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 12:59:01 +0100 Subject: [PATCH 16/46] Small changes around how we work with custom events in the analytics --- .../CookieHelperTests.cs | 52 ++ .../PlexRequests.Helpers.Tests.csproj | 237 ++--- PlexRequests.Helpers/Analytics/Action.cs | 3 +- PlexRequests.Helpers/Analytics/Analytics.cs | 53 +- PlexRequests.Helpers/Analytics/IAnalytics.cs | 18 +- PlexRequests.Helpers/CookieHelper.cs | 57 ++ .../PlexRequests.Helpers.csproj | 203 ++-- PlexRequests.UI.Tests/AdminModuleTests.cs | 724 ++++++++------- PlexRequests.UI.Tests/UserLoginModuleTests.cs | 876 +++++++++--------- PlexRequests.UI/Modules/AdminModule.cs | 11 +- PlexRequests.UI/Modules/BaseModule.cs | 148 +-- PlexRequests.UI/Modules/UserLoginModule.cs | 453 ++++----- .../Validators/PlexRequestsValidator.cs | 1 + PlexRequests.UI/Views/Shared/Blank.cshtml | 2 +- 14 files changed, 1498 insertions(+), 1340 deletions(-) create mode 100644 PlexRequests.Helpers.Tests/CookieHelperTests.cs create mode 100644 PlexRequests.Helpers/CookieHelper.cs diff --git a/PlexRequests.Helpers.Tests/CookieHelperTests.cs b/PlexRequests.Helpers.Tests/CookieHelperTests.cs new file mode 100644 index 000000000..c9a8205fb --- /dev/null +++ b/PlexRequests.Helpers.Tests/CookieHelperTests.cs @@ -0,0 +1,52 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: DateTimeHelperTests.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.Collections.Generic; + +using NUnit.Framework; + +namespace PlexRequests.Helpers.Tests +{ + [TestFixture] + public class CookieHelperTests + { + [TestCaseSource(nameof(GetAnalyticsClientId))] + public string TestGetAnalyticsClientId(Dictionary cookies) + { + return CookieHelper.GetAnalyticClientId(cookies); + } + + private static IEnumerable GetAnalyticsClientId + { + get + { + yield return new TestCaseData(new Dictionary()).Returns(string.Empty); + yield return new TestCaseData(new Dictionary { { "_ga", "GA1.1.306549087.1464005217" } }).Returns("306549087.1464005217"); + yield return new TestCaseData(new Dictionary { {"_ga", "GA1.1.306549087" } }).Returns(string.Empty); + } + } + } +} \ No newline at end of file diff --git a/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj b/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj index 308e966e7..0789e013c 100644 --- a/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj +++ b/PlexRequests.Helpers.Tests/PlexRequests.Helpers.Tests.csproj @@ -1,119 +1,120 @@ - - - - Debug - AnyCPU - {0E6395D3-B074-49E8-898D-0EB99E507E0E} - Library - Properties - PlexRequests.Helpers.Tests - PlexRequests.Helpers.Tests - v4.5 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll - True - - - ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll - True - - - ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - True - - - ..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll - True - - - ..\packages\Owin.1.0\lib\net40\Owin.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {1252336d-42a3-482a-804c-836e60173dfa} - PlexRequests.Helpers - - - - - - - False - - - False - - - False - - - False - - - - - - - + + + + Debug + AnyCPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E} + Library + Properties + PlexRequests.Helpers.Tests + PlexRequests.Helpers.Tests + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + True + + + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll + True + + + ..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll + True + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {1252336d-42a3-482a-804c-836e60173dfa} + PlexRequests.Helpers + + + + + + + False + + + False + + + False + + + False + + + + + + + \ No newline at end of file diff --git a/PlexRequests.Helpers/Analytics/Action.cs b/PlexRequests.Helpers/Analytics/Action.cs index a353dcc33..4a42a45be 100644 --- a/PlexRequests.Helpers/Analytics/Action.cs +++ b/PlexRequests.Helpers/Analytics/Action.cs @@ -34,6 +34,7 @@ namespace PlexRequests.Helpers.Analytics Create, Save, Update, - Start + Start, + View } } \ No newline at end of file diff --git a/PlexRequests.Helpers/Analytics/Analytics.cs b/PlexRequests.Helpers/Analytics/Analytics.cs index 4b4d74ed9..764295fa3 100644 --- a/PlexRequests.Helpers/Analytics/Analytics.cs +++ b/PlexRequests.Helpers/Analytics/Analytics.cs @@ -47,52 +47,51 @@ namespace PlexRequests.Helpers.Analytics private static Logger Log = LogManager.GetCurrentClassLogger(); - public void TrackEvent(Category category, Action action, string label, string username, int? value = null) + public void TrackEvent(Category category, Action action, string label, string username, string clientId, int? value = null) { var cat = category.ToString(); var act = action.ToString(); - Track(HitType.@event, username, cat, act, label, value); + Track(HitType.@event, username, cat, act, label, clientId, value); } - public async Task TrackEventAsync(Category category, Action action, string label, string username, int? value = null) + public async Task TrackEventAsync(Category category, Action action, string label, string username, string clientId, int? value = null) { var cat = category.ToString(); var act = action.ToString(); - await TrackAsync(HitType.@event, username, cat, act, label, value); + await TrackAsync(HitType.@event, username, cat, act, clientId, label, value); } - public void TrackPageview(Category category, Action action, string label, string username, int? value = null) + public void TrackPageview(Category category, Action action, string label, string username, string clientId, int? value = null) { var cat = category.ToString(); var act = action.ToString(); - Track(HitType.@pageview, username, cat, act, label, value); + Track(HitType.@pageview, username, cat, act, clientId, label, value); } - public async Task TrackPageviewAsync(Category category, Action action, string label, string username, int? value = null) + public async Task TrackPageviewAsync(Category category, Action action, string label, string username, string clientId, int? value = null) { var cat = category.ToString(); var act = action.ToString(); - await TrackAsync(HitType.@pageview, username, cat, act, label, value); + await TrackAsync(HitType.@pageview, username, cat, act, clientId, label, value); } - public void TrackException(string message, string username, bool fatal) + public void TrackException(string message, string username, string clientId, bool fatal) { var fatalInt = fatal ? 1 : 0; - Track(HitType.exception, message, fatalInt, username); + Track(HitType.exception, message, fatalInt, username, clientId); } - public async Task TrackExceptionAsync(string message, string username, bool fatal) + public async Task TrackExceptionAsync(string message, string username, string clientId, bool fatal) { var fatalInt = fatal ? 1 : 0; - await TrackAsync(HitType.exception, message, fatalInt, username); + await TrackAsync(HitType.exception, message, fatalInt, username, clientId); } - private void Track(HitType type, string username, string category, string action, string label, int? value = null) + private void Track(HitType type, string username, string category, string action, string clientId, string label, int? value = null) { if (string.IsNullOrEmpty(category)) throw new ArgumentNullException(nameof(category)); if (string.IsNullOrEmpty(action)) throw new ArgumentNullException(nameof(action)); - if (string.IsNullOrEmpty(username)) throw new ArgumentNullException(nameof(username)); - var postData = BuildRequestData(type, username, category, action, label, value, null, null); + var postData = BuildRequestData(type, username, category, action, clientId, label, value, null, null); var postDataString = postData .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) @@ -101,13 +100,12 @@ namespace PlexRequests.Helpers.Analytics SendRequest(postDataString); } - private async Task TrackAsync(HitType type, string username, string category, string action, string label, int? value = null) + private async Task TrackAsync(HitType type, string username, string category, string action, string clientId, string label, int? value = null) { if (string.IsNullOrEmpty(category)) throw new ArgumentNullException(nameof(category)); if (string.IsNullOrEmpty(action)) throw new ArgumentNullException(nameof(action)); - if (string.IsNullOrEmpty(username)) throw new ArgumentNullException(nameof(username)); - var postData = BuildRequestData(type, username, category, action, label, value, null, null); + var postData = BuildRequestData(type, username, category, action, clientId, label, value, null, null); var postDataString = postData .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) @@ -115,12 +113,11 @@ namespace PlexRequests.Helpers.Analytics await SendRequestAsync(postDataString); } - private async Task TrackAsync(HitType type, string message, int fatal, string username) + private async Task TrackAsync(HitType type, string message, int fatal, string username, string clientId) { if (string.IsNullOrEmpty(message)) throw new ArgumentNullException(nameof(message)); - if (string.IsNullOrEmpty(username)) throw new ArgumentNullException(nameof(username)); - var postData = BuildRequestData(type, username, null, null, null, null, message, fatal); + var postData = BuildRequestData(type, username, null, null, null, clientId, null, message, fatal); var postDataString = postData .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) @@ -129,12 +126,12 @@ namespace PlexRequests.Helpers.Analytics await SendRequestAsync(postDataString); } - private void Track(HitType type, string message, int fatal, string username) + private void Track(HitType type, string message, int fatal, string username, string clientId) { if (string.IsNullOrEmpty(message)) throw new ArgumentNullException(nameof(message)); if (string.IsNullOrEmpty(username)) throw new ArgumentNullException(nameof(username)); - var postData = BuildRequestData(type, username, null, null, null, null, message, fatal); + var postData = BuildRequestData(type, username, null, null, null, clientId, null, message, fatal); var postDataString = postData .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) @@ -196,20 +193,24 @@ namespace PlexRequests.Helpers.Analytics } } - private Dictionary BuildRequestData(HitType type, string username, string category, string action, string label, int? value, string exceptionDescription, int? fatal) + private Dictionary BuildRequestData(HitType type, string username, string category, string action, string clientId, string label, int? value, string exceptionDescription, int? fatal) { var postData = new Dictionary { { "v", "1" }, { "tid", TrackingId }, - { "t", type.ToString() }, - {"cid", Guid.NewGuid().ToString() } + { "t", type.ToString() } }; if (!string.IsNullOrEmpty(username)) { postData.Add("uid", username); } + + postData.Add("cid", !string.IsNullOrEmpty(clientId) + ? clientId + : Guid.NewGuid().ToString()); + if (!string.IsNullOrEmpty(label)) { postData.Add("el", label); diff --git a/PlexRequests.Helpers/Analytics/IAnalytics.cs b/PlexRequests.Helpers/Analytics/IAnalytics.cs index 4e228f545..d21dd18d1 100644 --- a/PlexRequests.Helpers/Analytics/IAnalytics.cs +++ b/PlexRequests.Helpers/Analytics/IAnalytics.cs @@ -37,8 +37,9 @@ namespace PlexRequests.Helpers.Analytics /// The action. /// The label. /// The username. + /// The client identifier. /// The value. - void TrackEvent(Category category, Action action, string label, string username, int? value = null); + void TrackEvent(Category category, Action action, string label, string username, string clientId, int? value = null); /// /// Tracks the event asynchronous. @@ -47,9 +48,10 @@ namespace PlexRequests.Helpers.Analytics /// The action. /// The label. /// The username. + /// The client identifier. /// The value. /// - Task TrackEventAsync(Category category, Action action, string label, string username, int? value = null); + Task TrackEventAsync(Category category, Action action, string label, string username, string clientId, int? value = null); /// /// Tracks the page view. @@ -58,8 +60,9 @@ namespace PlexRequests.Helpers.Analytics /// The action. /// The label. /// The username. + /// The client identifier. /// The value. - void TrackPageview(Category category, Action action, string label, string username, int? value = null); + void TrackPageview(Category category, Action action, string label, string username, string clientId, int? value = null); /// /// Tracks the page view asynchronous. @@ -68,25 +71,28 @@ namespace PlexRequests.Helpers.Analytics /// The action. /// The label. /// The username. + /// The client identifier. /// The value. /// - Task TrackPageviewAsync(Category category, Action action, string label, string username, int? value = null); + Task TrackPageviewAsync(Category category, Action action, string label, string username, string clientId, int? value = null); /// /// Tracks the exception. /// /// The message. /// The username. + /// The client identifier. /// if set to true [fatal]. - void TrackException(string message, string username, bool fatal); + void TrackException(string message, string username, string clientId, bool fatal); /// /// Tracks the exception asynchronous. /// /// The message. /// The username. + /// The client identifier. /// if set to true [fatal]. /// - Task TrackExceptionAsync(string message, string username, bool fatal); + Task TrackExceptionAsync(string message, string username, string clientId, bool fatal); } } \ No newline at end of file diff --git a/PlexRequests.Helpers/CookieHelper.cs b/PlexRequests.Helpers/CookieHelper.cs new file mode 100644 index 000000000..5d4b97a60 --- /dev/null +++ b/PlexRequests.Helpers/CookieHelper.cs @@ -0,0 +1,57 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: CookieHelper.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; +using System.Collections.Generic; + +namespace PlexRequests.Helpers +{ + public static class CookieHelper + { + private const string GaCookie = "_ga"; + + /// + /// Gets the analytic client identifier. + /// Example: Value = "GA1.1.306549087.1464005217" + /// + /// The cookies. + /// + public static string GetAnalyticClientId(IDictionary cookies) + { + var outString = string.Empty; + + if (cookies.TryGetValue(GaCookie, out outString)) + { + var split = outString.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + + return split.Length < 4 + ? string.Empty + : $"{split[2]}.{split[3]}"; + } + return string.Empty; + } + } +} \ No newline at end of file diff --git a/PlexRequests.Helpers/PlexRequests.Helpers.csproj b/PlexRequests.Helpers/PlexRequests.Helpers.csproj index 8bdfb5ed8..df0ffcf77 100644 --- a/PlexRequests.Helpers/PlexRequests.Helpers.csproj +++ b/PlexRequests.Helpers/PlexRequests.Helpers.csproj @@ -1,102 +1,103 @@ - - - - - Debug - AnyCPU - {1252336D-42A3-482A-804C-836E60173DFA} - Library - Properties - PlexRequests.Helpers - PlexRequests.Helpers - v4.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Hangfire.Core.1.5.7\lib\net45\Hangfire.Core.dll - True - - - ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll - True - - - ..\packages\NLog.4.3.4\lib\net45\NLog.dll - True - - - ..\packages\Owin.1.0\lib\net40\Owin.dll - True - - - - - - - - - - - - - ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {1252336D-42A3-482A-804C-836E60173DFA} + Library + Properties + PlexRequests.Helpers + PlexRequests.Helpers + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Hangfire.Core.1.5.7\lib\net45\Hangfire.Core.dll + True + + + ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll + True + + + ..\packages\NLog.4.3.4\lib\net45\NLog.dll + True + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + + + + + + + + + + + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.UI.Tests/AdminModuleTests.cs b/PlexRequests.UI.Tests/AdminModuleTests.cs index 66245d649..198be036f 100644 --- a/PlexRequests.UI.Tests/AdminModuleTests.cs +++ b/PlexRequests.UI.Tests/AdminModuleTests.cs @@ -1,361 +1,365 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: UserLoginModuleTests.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.Collections.Generic; -using System.Linq; - -using Moq; - -using Nancy; -using Nancy.Testing; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -using NUnit.Framework; - -using PlexRequests.Api.Interfaces; -using PlexRequests.Api.Models.Plex; -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.Services.Interfaces; -using PlexRequests.Store.Models; -using PlexRequests.Store.Repository; -using PlexRequests.UI.Models; -using PlexRequests.UI.Modules; -using PlexRequests.Helpers; -using PlexRequests.UI.Helpers; - -namespace PlexRequests.UI.Tests -{ - [TestFixture] - public class AdminModuleTests - { - private Mock> PlexRequestMock { get; set; } - private Mock> CpMock { get; set; } - private Mock> AuthMock { get; set; } - private Mock> PlexSettingsMock { get; set; } - private Mock> SonarrSettingsMock { get; set; } - private Mock> SickRageSettingsMock { get; set; } - private Mock> ScheduledJobsSettingsMock { get; set; } - private Mock> EmailMock { get; set; } - private Mock> PushbulletSettings { get; set; } - private Mock> PushoverSettings { get; set; } - private Mock> HeadphonesSettings { get; set; } - private Mock PlexMock { get; set; } - private Mock SonarrApiMock { get; set; } - private Mock PushbulletApi { get; set; } - private Mock PushoverApi { get; set; } - private Mock CpApi { get; set; } - private Mock RecorderMock { get; set; } - private Mock> LogRepo { get; set; } - private Mock NotificationService { get; set; } - private Mock Cache { get; set; } - private Mock> Log { get; set; } - private Mock> SlackSettings { get; set; } - private Mock> LandingPageSettings { get; set; } - private Mock SlackApi { get; set; } - - private ConfigurableBootstrapper Bootstrapper { get; set; } - - [SetUp] - public void Setup() - { - AuthMock = new Mock>(); - var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - - PlexMock = new Mock(); - PlexMock.Setup(x => x.SignIn("Username1", "Password1")) - .Returns(new PlexAuthentication { user = new User { authentication_token = "abc", title = "Username1" } }); - - PlexRequestMock = new Mock>(); - PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); - CpMock = new Mock>(); - PlexSettingsMock = new Mock>(); - SonarrApiMock = new Mock(); - SonarrSettingsMock = new Mock>(); - EmailMock = new Mock>(); - PushbulletApi = new Mock(); - PushbulletSettings = new Mock>(); - CpApi = new Mock(); - SickRageSettingsMock = new Mock>(); - LogRepo = new Mock>(); - PushoverSettings = new Mock>(); - PushoverApi = new Mock(); - NotificationService = new Mock(); - HeadphonesSettings = new Mock>(); - Cache = new Mock(); - Log = new Mock>(); - SlackApi = new Mock(); - SlackSettings = new Mock>(); - LandingPageSettings = new Mock>(); - ScheduledJobsSettingsMock = new Mock>(); - RecorderMock = new Mock(); - - - Bootstrapper = new ConfigurableBootstrapper(with => - { - with.Module(); - with.Dependency(AuthMock.Object); - with.Dependency(PlexRequestMock.Object); - with.Dependency(CpMock.Object); - with.Dependency(PlexSettingsMock.Object); - with.Dependency(SonarrApiMock.Object); - with.Dependency(SonarrSettingsMock.Object); - with.Dependency(PlexMock.Object); - with.Dependency(EmailMock.Object); - with.Dependency(PushbulletApi.Object); - with.Dependency(PushbulletSettings.Object); - with.Dependency(CpApi.Object); - with.Dependency(SickRageSettingsMock.Object); - with.Dependency(LogRepo.Object); - with.Dependency(PushoverSettings.Object); - with.Dependency(PushoverApi.Object); - with.Dependency(NotificationService.Object); - with.Dependency(HeadphonesSettings.Object); - with.Dependency(Cache.Object); - with.Dependency(Log.Object); - with.Dependency(SlackApi.Object); - with.Dependency(LandingPageSettings.Object); - with.Dependency(SlackSettings.Object); - with.Dependency(ScheduledJobsSettingsMock.Object); - with.Dependency(RecorderMock.Object); - with.RootPathProvider(); - with.RequestStartup((container, pipelines, context) => - { - context.CurrentUser = new UserIdentity { UserName = "user", Claims = new List {"Admin"} }; - }); - }); - - Bootstrapper.WithSession(new Dictionary()); - } - - [Test] - public void RequestAuthTokenTestNewSettings() - { - var browser = new Browser(Bootstrapper); - - var result = browser.Post("/admin/requestauth", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", "Username1"); - with.FormValue("password", "Password1"); - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(true)); - PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Once); - } - - [Test] - public void RequestAuthTokenTestEmptyCredentials() - { - var browser = new Browser(Bootstrapper); - - var result = browser.Post("/admin/requestauth", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", string.Empty); - with.FormValue("password", "Password1"); - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(false)); - Assert.That(body.Message, Is.Not.Empty); - - PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Never); - AuthMock.Verify(x => x.GetSettings(), Times.Never); - AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Never); - } - - [Test] - public void RequestAuthTokenTesPlexSignInFail() - { - var browser = new Browser(Bootstrapper); - - var result = browser.Post("/admin/requestauth", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", "Badusername"); - with.FormValue("password", "Password1"); - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(false)); - Assert.That(body.Message, Is.Not.Empty); - - PlexMock.Verify(x => x.SignIn("Badusername", "Password1"), Times.Once); - AuthMock.Verify(x => x.GetSettings(), Times.Never); - AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Never); - } - - [Test] - public void RequestAuthTokenTestExistingSettings() - { - AuthMock.Setup(x => x.GetSettings()).Returns(() => null); - var browser = new Browser(Bootstrapper); - - var result = browser.Post("/admin/requestauth", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", "Username1"); - with.FormValue("password", "Password1"); - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(true)); - - PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Once); - } - - [Test] - public void GetUsersSuccessfully() - { - var users = new PlexFriends { User = new[] { new UserFriends { Title = "abc2" }, } }; - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(users); - var browser = new Browser(Bootstrapper); - - var result = browser.Get("/admin/getusers", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", "Username1"); - with.FormValue("password", "Password1"); - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - var user = body["users"]; - Assert.That(body, Is.Not.Null); - Assert.That(user.ToString().Contains("abc"), Is.True); - - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - } - - [Test] - public void GetUsersReturnsNoUsers() - { - var users = new PlexFriends(); - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(users); - var browser = new Browser(Bootstrapper); - - var result = browser.Get("/admin/getusers", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", "Username1"); - with.FormValue("password", "Password1"); - - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body, Is.Not.Null); - Assert.That(string.IsNullOrWhiteSpace(body), Is.True); - - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - } - - [Test] - public void GetUsersReturnsNull() - { - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(() => null); - var browser = new Browser(Bootstrapper); - - var result = browser.Get("/admin/getusers", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", "Username1"); - with.FormValue("password", "Password1"); - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body, Is.Not.Null); - Assert.That(string.IsNullOrWhiteSpace(body), Is.True); - - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - } - - [Test] - public void GetUsersTokenIsNull() - { - AuthMock.Setup(x => x.GetSettings()).Returns(new AuthenticationSettings()); - var browser = new Browser(Bootstrapper); - - var result = browser.Get("/admin/getusers", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("username", "Username1"); - with.FormValue("password", "Password1"); - - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - var user = (string)body["users"]; - Assert.That(body, Is.Not.Null); - Assert.That(string.IsNullOrWhiteSpace(user), Is.True); - - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: UserLoginModuleTests.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.Collections.Generic; +using System.Linq; + +using Moq; + +using Nancy; +using Nancy.Testing; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using NUnit.Framework; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Api.Models.Plex; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Services.Interfaces; +using PlexRequests.Store.Models; +using PlexRequests.Store.Repository; +using PlexRequests.UI.Models; +using PlexRequests.UI.Modules; +using PlexRequests.Helpers; +using PlexRequests.Helpers.Analytics; +using PlexRequests.UI.Helpers; + +namespace PlexRequests.UI.Tests +{ + [TestFixture] + public class AdminModuleTests + { + private Mock> PlexRequestMock { get; set; } + private Mock> CpMock { get; set; } + private Mock> AuthMock { get; set; } + private Mock> PlexSettingsMock { get; set; } + private Mock> SonarrSettingsMock { get; set; } + private Mock> SickRageSettingsMock { get; set; } + private Mock> ScheduledJobsSettingsMock { get; set; } + private Mock> EmailMock { get; set; } + private Mock> PushbulletSettings { get; set; } + private Mock> PushoverSettings { get; set; } + private Mock> HeadphonesSettings { get; set; } + private Mock PlexMock { get; set; } + private Mock SonarrApiMock { get; set; } + private Mock PushbulletApi { get; set; } + private Mock PushoverApi { get; set; } + private Mock CpApi { get; set; } + private Mock RecorderMock { get; set; } + private Mock> LogRepo { get; set; } + private Mock NotificationService { get; set; } + private Mock Cache { get; set; } + private Mock> Log { get; set; } + private Mock> SlackSettings { get; set; } + private Mock> LandingPageSettings { get; set; } + private Mock SlackApi { get; set; } + private Mock IAnalytics { get; set; } + + private ConfigurableBootstrapper Bootstrapper { get; set; } + + [SetUp] + public void Setup() + { + AuthMock = new Mock>(); + var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + + PlexMock = new Mock(); + PlexMock.Setup(x => x.SignIn("Username1", "Password1")) + .Returns(new PlexAuthentication { user = new User { authentication_token = "abc", title = "Username1" } }); + + PlexRequestMock = new Mock>(); + PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); + CpMock = new Mock>(); + PlexSettingsMock = new Mock>(); + SonarrApiMock = new Mock(); + SonarrSettingsMock = new Mock>(); + EmailMock = new Mock>(); + PushbulletApi = new Mock(); + PushbulletSettings = new Mock>(); + CpApi = new Mock(); + SickRageSettingsMock = new Mock>(); + LogRepo = new Mock>(); + PushoverSettings = new Mock>(); + PushoverApi = new Mock(); + NotificationService = new Mock(); + HeadphonesSettings = new Mock>(); + Cache = new Mock(); + Log = new Mock>(); + SlackApi = new Mock(); + SlackSettings = new Mock>(); + LandingPageSettings = new Mock>(); + ScheduledJobsSettingsMock = new Mock>(); + RecorderMock = new Mock(); + IAnalytics = new Mock(); + + + Bootstrapper = new ConfigurableBootstrapper(with => + { + with.Module(); + with.Dependency(AuthMock.Object); + with.Dependency(PlexRequestMock.Object); + with.Dependency(CpMock.Object); + with.Dependency(PlexSettingsMock.Object); + with.Dependency(SonarrApiMock.Object); + with.Dependency(SonarrSettingsMock.Object); + with.Dependency(PlexMock.Object); + with.Dependency(EmailMock.Object); + with.Dependency(PushbulletApi.Object); + with.Dependency(PushbulletSettings.Object); + with.Dependency(CpApi.Object); + with.Dependency(SickRageSettingsMock.Object); + with.Dependency(LogRepo.Object); + with.Dependency(PushoverSettings.Object); + with.Dependency(PushoverApi.Object); + with.Dependency(NotificationService.Object); + with.Dependency(IAnalytics.Object); + with.Dependency(HeadphonesSettings.Object); + with.Dependency(Cache.Object); + with.Dependency(Log.Object); + with.Dependency(SlackApi.Object); + with.Dependency(LandingPageSettings.Object); + with.Dependency(SlackSettings.Object); + with.Dependency(ScheduledJobsSettingsMock.Object); + with.Dependency(RecorderMock.Object); + with.RootPathProvider(); + with.RequestStartup((container, pipelines, context) => + { + context.CurrentUser = new UserIdentity { UserName = "user", Claims = new List {"Admin"} }; + }); + }); + + Bootstrapper.WithSession(new Dictionary()); + } + + [Test] + public void RequestAuthTokenTestNewSettings() + { + var browser = new Browser(Bootstrapper); + + var result = browser.Post("/admin/requestauth", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", "Username1"); + with.FormValue("password", "Password1"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(true)); + PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Once); + } + + [Test] + public void RequestAuthTokenTestEmptyCredentials() + { + var browser = new Browser(Bootstrapper); + + var result = browser.Post("/admin/requestauth", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", string.Empty); + with.FormValue("password", "Password1"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(false)); + Assert.That(body.Message, Is.Not.Empty); + + PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Never); + AuthMock.Verify(x => x.GetSettings(), Times.Never); + AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Never); + } + + [Test] + public void RequestAuthTokenTesPlexSignInFail() + { + var browser = new Browser(Bootstrapper); + + var result = browser.Post("/admin/requestauth", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", "Badusername"); + with.FormValue("password", "Password1"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(false)); + Assert.That(body.Message, Is.Not.Empty); + + PlexMock.Verify(x => x.SignIn("Badusername", "Password1"), Times.Once); + AuthMock.Verify(x => x.GetSettings(), Times.Never); + AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Never); + } + + [Test] + public void RequestAuthTokenTestExistingSettings() + { + AuthMock.Setup(x => x.GetSettings()).Returns(() => null); + var browser = new Browser(Bootstrapper); + + var result = browser.Post("/admin/requestauth", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", "Username1"); + with.FormValue("password", "Password1"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(true)); + + PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.SaveSettings(It.IsAny()), Times.Once); + } + + [Test] + public void GetUsersSuccessfully() + { + var users = new PlexFriends { User = new[] { new UserFriends { Title = "abc2" }, } }; + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(users); + var browser = new Browser(Bootstrapper); + + var result = browser.Get("/admin/getusers", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", "Username1"); + with.FormValue("password", "Password1"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + var user = body["users"]; + Assert.That(body, Is.Not.Null); + Assert.That(user.ToString().Contains("abc"), Is.True); + + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + } + + [Test] + public void GetUsersReturnsNoUsers() + { + var users = new PlexFriends(); + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(users); + var browser = new Browser(Bootstrapper); + + var result = browser.Get("/admin/getusers", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", "Username1"); + with.FormValue("password", "Password1"); + + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body, Is.Not.Null); + Assert.That(string.IsNullOrWhiteSpace(body), Is.True); + + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + } + + [Test] + public void GetUsersReturnsNull() + { + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(() => null); + var browser = new Browser(Bootstrapper); + + var result = browser.Get("/admin/getusers", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", "Username1"); + with.FormValue("password", "Password1"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body, Is.Not.Null); + Assert.That(string.IsNullOrWhiteSpace(body), Is.True); + + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + } + + [Test] + public void GetUsersTokenIsNull() + { + AuthMock.Setup(x => x.GetSettings()).Returns(new AuthenticationSettings()); + var browser = new Browser(Bootstrapper); + + var result = browser.Get("/admin/getusers", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("username", "Username1"); + with.FormValue("password", "Password1"); + + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + var user = (string)body["users"]; + Assert.That(body, Is.Not.Null); + Assert.That(string.IsNullOrWhiteSpace(user), Is.True); + + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + } + } } \ No newline at end of file diff --git a/PlexRequests.UI.Tests/UserLoginModuleTests.cs b/PlexRequests.UI.Tests/UserLoginModuleTests.cs index 22d000575..c962fa335 100644 --- a/PlexRequests.UI.Tests/UserLoginModuleTests.cs +++ b/PlexRequests.UI.Tests/UserLoginModuleTests.cs @@ -1,437 +1,441 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: UserLoginModuleTests.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.Collections.Generic; -using System.Threading.Tasks; - -using Moq; - -using Nancy; -using Nancy.Testing; - -using Newtonsoft.Json; - -using NUnit.Framework; - -using PlexRequests.Api.Interfaces; -using PlexRequests.Api.Models.Plex; -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.UI.Models; -using PlexRequests.UI.Modules; - -namespace PlexRequests.UI.Tests -{ - [TestFixture] - public class UserLoginModuleTests - { - private Mock> AuthMock { get; set; } - private Mock> PlexRequestMock { get; set; } - private Mock> LandingPageMock { get; set; } - private ConfigurableBootstrapper Bootstrapper { get; set; } - private Mock PlexMock { get; set; } - - [SetUp] - public void Setup() - { - AuthMock = new Mock>(); - PlexMock = new Mock(); - LandingPageMock = new Mock>(); - PlexRequestMock = new Mock>(); - PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); - PlexRequestMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(new PlexRequestSettings())); - LandingPageMock.Setup(x => x.GetSettings()).Returns(new LandingPageSettings()); - Bootstrapper = new ConfigurableBootstrapper(with => - { - with.Module(); - with.Dependency(PlexRequestMock.Object); - with.Dependency(AuthMock.Object); - with.Dependency(PlexMock.Object); - with.Dependency(LandingPageMock.Object); - with.RootPathProvider(); - }); - } - - [Test] - public void LoginWithoutAuthentication() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "abc"); - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); - } - - [Test] - public void LoginWithoutAuthenticationWithEmptyUsername() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", string.Empty); - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(false)); - AuthMock.Verify(x => x.GetSettings(), Times.Never); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); - } - - [Test] - public void LoginWithUsernameSuccessfully() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" }; - var plexFriends = new PlexFriends - { - User = new[] - { - new UserFriends - { - Title = "abc", - }, - } - }; - - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); - PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "abc"); - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); - } - - [Test] - public void LoginWithUsernameUnSuccessfully() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" }; - var plexFriends = new PlexFriends - { - User = new[] - { - new UserFriends - { - Username = "aaaa", - }, - } - }; - - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); - PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "abc"); - }); - - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(false)); - Assert.That(body.Message, Is.Not.Empty); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); - } - - [Test] - public void LoginWithUsernameAndPasswordSuccessfully() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" }; - var plexFriends = new PlexFriends - { - User = new[] - { - new UserFriends - { - Title = "abc", - } - } - }; - var plexAuth = new PlexAuthentication - { - user = new User - { - authentication_token = "abc" - } - }; - - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); - PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); - PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "abc"); - with.FormValue("Password", "abc"); - }); - - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); - } - - [Test] - public void LoginWithUsernameAndPasswordUnSuccessfully() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" }; - var plexFriends = new PlexFriends - { - User = new[] - { - new UserFriends - { - Username = "abc", - }, - } - }; - var plexAuth = new PlexAuthentication - { - user = null - }; - - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); - PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); - - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "abc"); - with.FormValue("Password", "abc"); - }); - - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(false)); - Assert.That(body.Message, Is.Not.Empty); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); - } - - [Test] - public void AttemptToLoginAsDeniedUser() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = false, DeniedUsers = "abc", PlexAuthToken = "abc" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "abc"); - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(false)); - Assert.That(body.Message, Is.Not.Empty); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); - } - - [Test] - public void Logout() - { - Bootstrapper.WithSession(new Dictionary { { SessionKeys.UsernameKey, "abc" } }); - - var browser = new Browser(Bootstrapper); - var result = browser.Get("/userlogin/logout", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - }); - - Assert.That(HttpStatusCode.SeeOther, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); - } - - [Test] - public void LoginWithOwnerUsernameSuccessfully() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" }; - var plexFriends = new PlexFriends - { - User = new[] - { - new UserFriends() - } - }; - - var account = new PlexAccount { Username = "Jamie" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); - PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(account); - PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(new PlexAuthentication { user = new User { username = "Jamie" } }); - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "Jamie"); - }); - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("Jamie")); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); - } - - [Test] - public void LoginWithOwnerUsernameAndPasswordSuccessfully() - { - var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" }; - var plexFriends = new PlexFriends - { - User = new[] - { - new UserFriends() - } - }; - var plexAuth = new PlexAuthentication - { - user = new User - { - authentication_token = "abc", - username = "Jamie" - } - }; - - var account = new PlexAccount { Username = "Jamie" }; - - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); - PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); - PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); - PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(account); - - Bootstrapper.WithSession(new Dictionary()); - - var browser = new Browser(Bootstrapper); - var result = browser.Post("/userlogin", with => - { - with.HttpRequest(); - with.Header("Accept", "application/json"); - with.FormValue("Username", "jamie"); - with.FormValue("Password", "abc"); - }); - - - Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); - Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("jamie")); - - var body = JsonConvert.DeserializeObject(result.Body.AsString()); - Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); - PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); - PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); - } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: UserLoginModuleTests.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.Collections.Generic; +using System.Threading.Tasks; + +using Moq; + +using Nancy; +using Nancy.Testing; + +using Newtonsoft.Json; + +using NUnit.Framework; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Api.Models.Plex; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers.Analytics; +using PlexRequests.UI.Models; +using PlexRequests.UI.Modules; + +namespace PlexRequests.UI.Tests +{ + [TestFixture] + public class UserLoginModuleTests + { + private Mock> AuthMock { get; set; } + private Mock> PlexRequestMock { get; set; } + private Mock> LandingPageMock { get; set; } + private ConfigurableBootstrapper Bootstrapper { get; set; } + private Mock PlexMock { get; set; } + private Mock IAnalytics { get; set; } + + [SetUp] + public void Setup() + { + AuthMock = new Mock>(); + PlexMock = new Mock(); + LandingPageMock = new Mock>(); + PlexRequestMock = new Mock>(); + PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); + PlexRequestMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(new PlexRequestSettings())); + LandingPageMock.Setup(x => x.GetSettings()).Returns(new LandingPageSettings()); + IAnalytics = new Mock(); + Bootstrapper = new ConfigurableBootstrapper(with => + { + with.Module(); + with.Dependency(PlexRequestMock.Object); + with.Dependency(AuthMock.Object); + with.Dependency(PlexMock.Object); + with.Dependency(LandingPageMock.Object); + with.Dependency(IAnalytics.Object); + with.RootPathProvider(); + }); + } + + [Test] + public void LoginWithoutAuthentication() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "abc"); + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(true)); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); + } + + [Test] + public void LoginWithoutAuthenticationWithEmptyUsername() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", string.Empty); + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(false)); + AuthMock.Verify(x => x.GetSettings(), Times.Never); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); + } + + [Test] + public void LoginWithUsernameSuccessfully() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" }; + var plexFriends = new PlexFriends + { + User = new[] + { + new UserFriends + { + Title = "abc", + }, + } + }; + + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); + PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "abc"); + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(true)); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); + } + + [Test] + public void LoginWithUsernameUnSuccessfully() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" }; + var plexFriends = new PlexFriends + { + User = new[] + { + new UserFriends + { + Username = "aaaa", + }, + } + }; + + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); + PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "abc"); + }); + + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(false)); + Assert.That(body.Message, Is.Not.Empty); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); + } + + [Test] + public void LoginWithUsernameAndPasswordSuccessfully() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" }; + var plexFriends = new PlexFriends + { + User = new[] + { + new UserFriends + { + Title = "abc", + } + } + }; + var plexAuth = new PlexAuthentication + { + user = new User + { + authentication_token = "abc" + } + }; + + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); + PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); + PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "abc"); + with.FormValue("Password", "abc"); + }); + + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(true)); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); + } + + [Test] + public void LoginWithUsernameAndPasswordUnSuccessfully() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" }; + var plexFriends = new PlexFriends + { + User = new[] + { + new UserFriends + { + Username = "abc", + }, + } + }; + var plexAuth = new PlexAuthentication + { + user = null + }; + + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); + PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); + + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "abc"); + with.FormValue("Password", "abc"); + }); + + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(false)); + Assert.That(body.Message, Is.Not.Empty); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); + } + + [Test] + public void AttemptToLoginAsDeniedUser() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = false, DeniedUsers = "abc", PlexAuthToken = "abc" }; + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "abc"); + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(false)); + Assert.That(body.Message, Is.Not.Empty); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); + } + + [Test] + public void Logout() + { + Bootstrapper.WithSession(new Dictionary { { SessionKeys.UsernameKey, "abc" } }); + + var browser = new Browser(Bootstrapper); + var result = browser.Get("/userlogin/logout", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + }); + + Assert.That(HttpStatusCode.SeeOther, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); + } + + [Test] + public void LoginWithOwnerUsernameSuccessfully() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" }; + var plexFriends = new PlexFriends + { + User = new[] + { + new UserFriends() + } + }; + + var account = new PlexAccount { Username = "Jamie" }; + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); + PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(account); + PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(new PlexAuthentication { user = new User { username = "Jamie" } }); + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "Jamie"); + }); + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("Jamie")); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(true)); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); + } + + [Test] + public void LoginWithOwnerUsernameAndPasswordSuccessfully() + { + var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" }; + var plexFriends = new PlexFriends + { + User = new[] + { + new UserFriends() + } + }; + var plexAuth = new PlexAuthentication + { + user = new User + { + authentication_token = "abc", + username = "Jamie" + } + }; + + var account = new PlexAccount { Username = "Jamie" }; + + AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); + PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); + PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(account); + + Bootstrapper.WithSession(new Dictionary()); + + var browser = new Browser(Bootstrapper); + var result = browser.Post("/userlogin", with => + { + with.HttpRequest(); + with.Header("Accept", "application/json"); + with.FormValue("Username", "jamie"); + with.FormValue("Password", "abc"); + }); + + + Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); + Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("jamie")); + + var body = JsonConvert.DeserializeObject(result.Body.AsString()); + Assert.That(body.Result, Is.EqualTo(true)); + AuthMock.Verify(x => x.GetSettings(), Times.Once); + PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); + } + } } \ No newline at end of file diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index c22734b9f..5b8f0a103 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -32,7 +32,6 @@ using System; using System.Diagnostics; using System.Threading.Tasks; using System.Collections.Generic; -using System.Dynamic; using System.Linq; using System.Net; @@ -52,6 +51,7 @@ using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels; using PlexRequests.Helpers; +using PlexRequests.Helpers.Analytics; using PlexRequests.Helpers.Exceptions; using PlexRequests.Services.Interfaces; using PlexRequests.Services.Notification; @@ -60,6 +60,7 @@ using PlexRequests.Store.Repository; using PlexRequests.UI.Helpers; using PlexRequests.UI.Models; +using Action = PlexRequests.Helpers.Analytics.Action; namespace PlexRequests.UI.Modules { @@ -89,6 +90,7 @@ namespace PlexRequests.UI.Modules private ISettingsService ScheduledJobSettings { get; } private ISlackApi SlackApi { get; } private IJobRecord JobRecorder { get; } + private IAnalytics Analytics { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); public AdminModule(ISettingsService prService, @@ -111,7 +113,7 @@ namespace PlexRequests.UI.Modules ISettingsService logs, ICacheProvider cache, ISettingsService slackSettings, ISlackApi slackApi, ISettingsService lp, - ISettingsService scheduler, IJobRecord rec) : base("admin", prService) + ISettingsService scheduler, IJobRecord rec, IAnalytics analytics) : base("admin", prService) { PrService = prService; CpService = cpService; @@ -137,6 +139,7 @@ namespace PlexRequests.UI.Modules LandingSettings = lp; ScheduledJobSettings = scheduler; JobRecorder = rec; + Analytics = analytics; this.RequiresClaims(UserClaims.Admin); @@ -237,7 +240,7 @@ namespace PlexRequests.UI.Modules return View["Settings", settings]; } - private Response SaveAdmin() + private async Task SaveAdmin() { var model = this.Bind(); var valid = this.Validate(model); @@ -254,6 +257,8 @@ namespace PlexRequests.UI.Modules } } var result = PrService.SaveSettings(model); + + await Analytics.TrackEventAsync(Category.Admin, Action.Save, "PlexRequestSettings", Username, CookieHelper.GetAnalyticClientId(Cookies)); return Response.AsJson(result ? new JsonResponseModel { Result = true } : new JsonResponseModel { Result = false, Message = "We could not save to the database, please try again" }); diff --git a/PlexRequests.UI/Modules/BaseModule.cs b/PlexRequests.UI/Modules/BaseModule.cs index 2ebce8fa7..14b24141e 100644 --- a/PlexRequests.UI/Modules/BaseModule.cs +++ b/PlexRequests.UI/Modules/BaseModule.cs @@ -1,68 +1,69 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: BaseModule.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; -using System.Linq; - -using Nancy; - -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.Helpers; -using PlexRequests.UI.Models; - -namespace PlexRequests.UI.Modules -{ - public abstract class BaseModule : NancyModule - { - protected string BaseUrl { get; set; } - - protected BaseModule(ISettingsService settingsService) - { - var settings = settingsService.GetSettings(); - var baseUrl = settings.BaseUrl; - BaseUrl = baseUrl; - - var modulePath = string.IsNullOrEmpty(baseUrl) ? string.Empty : baseUrl; - - ModulePath = modulePath; - } - - protected BaseModule(string modulePath, ISettingsService settingsService) - { - var settings = settingsService.GetSettings(); - var baseUrl = settings.BaseUrl; - BaseUrl = baseUrl; - - var settingModulePath = string.IsNullOrEmpty(baseUrl) ? modulePath : $"{baseUrl}/{modulePath}"; - - ModulePath = settingModulePath; - } - - private int _dateTimeOffset = -1; +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: BaseModule.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; +using System.Collections.Generic; +using System.Linq; + +using Nancy; + +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers; +using PlexRequests.UI.Models; + +namespace PlexRequests.UI.Modules +{ + public abstract class BaseModule : NancyModule + { + protected string BaseUrl { get; set; } + + protected BaseModule(ISettingsService settingsService) + { + var settings = settingsService.GetSettings(); + var baseUrl = settings.BaseUrl; + BaseUrl = baseUrl; + + var modulePath = string.IsNullOrEmpty(baseUrl) ? string.Empty : baseUrl; + + ModulePath = modulePath; + } + + protected BaseModule(string modulePath, ISettingsService settingsService) + { + var settings = settingsService.GetSettings(); + var baseUrl = settings.BaseUrl; + BaseUrl = baseUrl; + + var settingModulePath = string.IsNullOrEmpty(baseUrl) ? modulePath : $"{baseUrl}/{modulePath}"; + + ModulePath = settingModulePath; + } + + private int _dateTimeOffset = -1; protected int DateTimeOffset { get @@ -73,7 +74,7 @@ namespace PlexRequests.UI.Modules } return _dateTimeOffset; } - } + } private string _username; protected string Username @@ -82,12 +83,21 @@ namespace PlexRequests.UI.Modules { if (string.IsNullOrEmpty(_username)) { - _username = Session[SessionKeys.UsernameKey].ToString(); + try + { + _username = Session[SessionKeys.UsernameKey].ToString(); + } + catch (Exception) + { + return string.Empty; + } } return _username; } } + protected IDictionary Cookies => Request.Cookies; + protected bool IsAdmin { get @@ -100,6 +110,6 @@ namespace PlexRequests.UI.Modules return claims.Contains(UserClaims.Admin) || claims.Contains(UserClaims.PowerUser); } } - - } + + } } \ No newline at end of file diff --git a/PlexRequests.UI/Modules/UserLoginModule.cs b/PlexRequests.UI/Modules/UserLoginModule.cs index cfa0c03a9..2cb97ff11 100644 --- a/PlexRequests.UI/Modules/UserLoginModule.cs +++ b/PlexRequests.UI/Modules/UserLoginModule.cs @@ -1,220 +1,235 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: UserLoginModule.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; -using System.Linq; -using System.Threading.Tasks; - -using Nancy; -using Nancy.Extensions; -using Nancy.Responses.Negotiation; - -using NLog; - -using PlexRequests.Api.Interfaces; -using PlexRequests.Api.Models.Plex; -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.UI.Models; - -namespace PlexRequests.UI.Modules -{ - public class UserLoginModule : BaseModule - { - public UserLoginModule(ISettingsService auth, IPlexApi api, ISettingsService pr, ISettingsService lp) : base("userlogin", pr) - { - AuthService = auth; - LandingPageSettings = lp; - Api = api; - Get["/", true] = async (x, ct) => await Index(); - Post["/"] = x => LoginUser(); - Get["/logout"] = x => Logout(); - } - - private ISettingsService AuthService { get; } - private ISettingsService LandingPageSettings { get; } - private IPlexApi Api { get; } - - private static Logger Log = LogManager.GetCurrentClassLogger(); - - public async Task Index() - { - var query = Request.Query["landing"]; - var landingCheck = (bool?)query ?? true; - if (landingCheck) - { - var landingSettings = await LandingPageSettings.GetSettingsAsync(); - - if (landingSettings.Enabled) - { - if (landingSettings.BeforeLogin) - { - var model = new LandingPageViewModel - { - Enabled = landingSettings.Enabled, - Id = landingSettings.Id, - EnabledNoticeTime = landingSettings.EnabledNoticeTime, - NoticeEnable = landingSettings.NoticeEnable, - NoticeEnd = landingSettings.NoticeEnd, - NoticeMessage = landingSettings.NoticeMessage, - NoticeStart = landingSettings.NoticeStart, - ContinueUrl = landingSettings.BeforeLogin ? $"userlogin" : $"search" - }; - - return View["Landing/Index", model]; - } - } - } - var settings = await AuthService.GetSettingsAsync(); - return View["Index", settings]; - } - - private Response LoginUser() - { - var dateTimeOffset = Request.Form.DateTimeOffset; - var username = Request.Form.username.Value; - Log.Debug("Username \"{0}\" attempting to login", username); - if (string.IsNullOrWhiteSpace(username)) - { - return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" }); - } - - var authenticated = false; - - var settings = AuthService.GetSettings(); - - if (IsUserInDeniedList(username, settings)) - { - Log.Debug("User is in denied list, not allowing them to authenticate"); - return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" }); - } - - var password = string.Empty; - if (settings.UsePassword) - { - Log.Debug("Using password"); - password = Request.Form.password.Value; - } - - - if (settings.UserAuthentication && settings.UsePassword) // Authenticate with Plex - { - Log.Debug("Need to auth and also provide pass"); - var signedIn = (PlexAuthentication)Api.SignIn(username, password); - if (signedIn.user?.authentication_token != null) - { - Log.Debug("Correct credentials, checking if the user is account owner or in the friends list"); - if (CheckIfUserIsOwner(settings.PlexAuthToken, signedIn.user?.username)) - { - Log.Debug("User is the account owner"); - authenticated = true; - } - else - { - authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken); - Log.Debug("Friends list result = {0}", authenticated); - } - } - } - else if (settings.UserAuthentication) // Check against the users in Plex - { - Log.Debug("Need to auth"); - authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken); - if (CheckIfUserIsOwner(settings.PlexAuthToken, username)) - { - Log.Debug("User is the account owner"); - authenticated = true; - } - Log.Debug("Friends list result = {0}", authenticated); - } - else if (!settings.UserAuthentication) // No auth, let them pass! - { - Log.Debug("No need to auth"); - authenticated = true; - } - - if (authenticated) - { - Log.Debug("We are authenticated! Setting session."); - // Add to the session (Used in the BaseModules) - Session[SessionKeys.UsernameKey] = (string)username; - } - - Session[SessionKeys.ClientDateTimeOffsetKey] = (int)dateTimeOffset; - - if (!authenticated) - { - return Response.AsJson(new JsonResponseModel {Result = false, Message = "Incorrect User or Password"}); - } - - var landingSettings = LandingPageSettings.GetSettings(); - - if (landingSettings.Enabled) - { - if (!landingSettings.BeforeLogin) - return Response.AsJson(new JsonResponseModel { Result = true, Message = "landing" }); - } - return Response.AsJson(new JsonResponseModel {Result = true, Message = "search" }); - } - - - - private Response Logout() - { - Log.Debug("Logging Out"); - if (Session[SessionKeys.UsernameKey] != null) - { - Session.Delete(SessionKeys.UsernameKey); - } - return Context.GetRedirect(!string.IsNullOrEmpty(BaseUrl) - ? $"~/{BaseUrl}/userlogin" - : "~/userlogin"); - } - - private bool CheckIfUserIsOwner(string authToken, string userName) - { - var userAccount = Api.GetAccount(authToken); - if (userAccount == null) - { - return false; - } - return userAccount.Username != null && userAccount.Username.Equals(userName, StringComparison.CurrentCultureIgnoreCase); - } - - private bool CheckIfUserIsInPlexFriends(string username, string authToken) - { - var users = Api.GetUsers(authToken); - var allUsers = users?.User?.Where(x => !string.IsNullOrEmpty(x.Title)); - return allUsers != null && allUsers.Any(x => x.Title.Equals(username, StringComparison.CurrentCultureIgnoreCase)); - } - - private bool IsUserInDeniedList(string username, AuthenticationSettings settings) - { - return settings.DeniedUserList.Any(x => x.Equals(username)); - } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: UserLoginModule.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; +using System.Linq; +using System.Threading.Tasks; + +using Nancy; +using Nancy.Extensions; +using Nancy.Responses.Negotiation; + +using NLog; + +using PlexRequests.Api.Interfaces; +using PlexRequests.Api.Models.Plex; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers; +using PlexRequests.Helpers.Analytics; +using PlexRequests.UI.Models; + +using Action = PlexRequests.Helpers.Analytics.Action; + +namespace PlexRequests.UI.Modules +{ + public class UserLoginModule : BaseModule + { + public UserLoginModule(ISettingsService auth, IPlexApi api, ISettingsService pr, ISettingsService lp, IAnalytics a) : base("userlogin", pr) + { + AuthService = auth; + LandingPageSettings = lp; + Analytics = a; + Api = api; + Get["/", true] = async (x, ct) => await Index(); + Post["/"] = x => LoginUser(); + Get["/logout"] = x => Logout(); + } + + private ISettingsService AuthService { get; } + private ISettingsService LandingPageSettings { get; } + private IPlexApi Api { get; } + private IAnalytics Analytics { get; } + + private static Logger Log = LogManager.GetCurrentClassLogger(); + + public async Task Index() + { + var query = Request.Query["landing"]; + var landingCheck = (bool?)query ?? true; + if (landingCheck) + { + var landingSettings = await LandingPageSettings.GetSettingsAsync(); + + if (landingSettings.Enabled) + { + + if (landingSettings.BeforeLogin) + { + await + Analytics.TrackEventAsync( + Category.LandingPage, + Action.View, + "Going To LandingPage before login", + Username, + CookieHelper.GetAnalyticClientId(Cookies)); + + var model = new LandingPageViewModel + { + Enabled = landingSettings.Enabled, + Id = landingSettings.Id, + EnabledNoticeTime = landingSettings.EnabledNoticeTime, + NoticeEnable = landingSettings.NoticeEnable, + NoticeEnd = landingSettings.NoticeEnd, + NoticeMessage = landingSettings.NoticeMessage, + NoticeStart = landingSettings.NoticeStart, + ContinueUrl = landingSettings.BeforeLogin ? $"userlogin" : $"search" + }; + + return View["Landing/Index", model]; + } + } + } + var settings = await AuthService.GetSettingsAsync(); + return View["Index", settings]; + } + + private Response LoginUser() + { + var dateTimeOffset = Request.Form.DateTimeOffset; + var username = Request.Form.username.Value; + Log.Debug("Username \"{0}\" attempting to login", username); + if (string.IsNullOrWhiteSpace(username)) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" }); + } + + var authenticated = false; + + var settings = AuthService.GetSettings(); + + if (IsUserInDeniedList(username, settings)) + { + Log.Debug("User is in denied list, not allowing them to authenticate"); + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" }); + } + + var password = string.Empty; + if (settings.UsePassword) + { + Log.Debug("Using password"); + password = Request.Form.password.Value; + } + + + if (settings.UserAuthentication && settings.UsePassword) // Authenticate with Plex + { + Log.Debug("Need to auth and also provide pass"); + var signedIn = (PlexAuthentication)Api.SignIn(username, password); + if (signedIn.user?.authentication_token != null) + { + Log.Debug("Correct credentials, checking if the user is account owner or in the friends list"); + if (CheckIfUserIsOwner(settings.PlexAuthToken, signedIn.user?.username)) + { + Log.Debug("User is the account owner"); + authenticated = true; + } + else + { + authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken); + Log.Debug("Friends list result = {0}", authenticated); + } + } + } + else if (settings.UserAuthentication) // Check against the users in Plex + { + Log.Debug("Need to auth"); + authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken); + if (CheckIfUserIsOwner(settings.PlexAuthToken, username)) + { + Log.Debug("User is the account owner"); + authenticated = true; + } + Log.Debug("Friends list result = {0}", authenticated); + } + else if (!settings.UserAuthentication) // No auth, let them pass! + { + Log.Debug("No need to auth"); + authenticated = true; + } + + if (authenticated) + { + Log.Debug("We are authenticated! Setting session."); + // Add to the session (Used in the BaseModules) + Session[SessionKeys.UsernameKey] = (string)username; + } + + Session[SessionKeys.ClientDateTimeOffsetKey] = (int)dateTimeOffset; + + if (!authenticated) + { + return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" }); + } + + var landingSettings = LandingPageSettings.GetSettings(); + + if (landingSettings.Enabled) + { + if (!landingSettings.BeforeLogin) + return Response.AsJson(new JsonResponseModel { Result = true, Message = "landing" }); + } + return Response.AsJson(new JsonResponseModel { Result = true, Message = "search" }); + } + + + + private Response Logout() + { + Log.Debug("Logging Out"); + if (Session[SessionKeys.UsernameKey] != null) + { + Session.Delete(SessionKeys.UsernameKey); + } + return Context.GetRedirect(!string.IsNullOrEmpty(BaseUrl) + ? $"~/{BaseUrl}/userlogin" + : "~/userlogin"); + } + + private bool CheckIfUserIsOwner(string authToken, string userName) + { + var userAccount = Api.GetAccount(authToken); + if (userAccount == null) + { + return false; + } + return userAccount.Username != null && userAccount.Username.Equals(userName, StringComparison.CurrentCultureIgnoreCase); + } + + private bool CheckIfUserIsInPlexFriends(string username, string authToken) + { + var users = Api.GetUsers(authToken); + var allUsers = users?.User?.Where(x => !string.IsNullOrEmpty(x.Title)); + return allUsers != null && allUsers.Any(x => x.Title.Equals(username, StringComparison.CurrentCultureIgnoreCase)); + } + + private bool IsUserInDeniedList(string username, AuthenticationSettings settings) + { + return settings.DeniedUserList.Any(x => x.Equals(username)); + } + } } \ No newline at end of file diff --git a/PlexRequests.UI/Validators/PlexRequestsValidator.cs b/PlexRequests.UI/Validators/PlexRequestsValidator.cs index 6f8ba4d3e..c82817185 100644 --- a/PlexRequests.UI/Validators/PlexRequestsValidator.cs +++ b/PlexRequests.UI/Validators/PlexRequestsValidator.cs @@ -45,6 +45,7 @@ namespace PlexRequests.UI.Validators RuleFor(x => x.BaseUrl).NotEqual("updatechecker").WithMessage("You cannot use 'updatechecker' as this is reserved by the application."); RuleFor(x => x.BaseUrl).NotEqual("usermanagement").WithMessage("You cannot use 'usermanagement' as this is reserved by the application."); RuleFor(x => x.BaseUrl).NotEqual("api").WithMessage("You cannot use 'api' as this is reserved by the application."); + RuleFor(x => x.BaseUrl).NotEqual("landing").WithMessage("You cannot use 'landing' as this is reserved by the application."); } } } \ No newline at end of file diff --git a/PlexRequests.UI/Views/Shared/Blank.cshtml b/PlexRequests.UI/Views/Shared/Blank.cshtml index d5b1f73eb..cafdf0d63 100644 --- a/PlexRequests.UI/Views/Shared/Blank.cshtml +++ b/PlexRequests.UI/Views/Shared/Blank.cshtml @@ -17,7 +17,7 @@ Plex Requests - + @Html.LoadAnalytics() @Html.LoadAssets() From 73f02b8e879aee5748f7a143b9279b1ee94d2d4c Mon Sep 17 00:00:00 2001 From: Jamie Date: Wed, 22 Jun 2016 13:37:18 +0100 Subject: [PATCH 17/46] Update appveyor.yml --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index cfef4c77b..f89de2ad2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,9 +3,9 @@ configuration: Release assembly_info: patch: true file: '**\AssemblyInfo.*' - assembly_version: '1.8.1' + assembly_version: '1.8.2' assembly_file_version: '{version}' - assembly_informational_version: '1.8.1' + assembly_informational_version: '1.8.2' before_build: - cmd: appveyor-retry nuget restore build: From f834e9635c77b2b65fb90dc5baca5252eab0b9c2 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 13:50:17 +0100 Subject: [PATCH 18/46] Fixed a circular reference issue --- PlexRequests.UI/Modules/AdminModule.cs | 2 +- PlexRequests.UI/Views/Admin/Settings.cshtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index 5b8f0a103..8e0ff9363 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -148,7 +148,7 @@ namespace PlexRequests.UI.Modules Get["/authentication", true] = async (x, ct) => await Authentication(); Post["/authentication", true] = async (x, ct) => await SaveAuthentication(); - Post["/"] = _ => SaveAdmin(); + Post["/", true] = async (x, ct) => await SaveAdmin(); Post["/requestauth"] = _ => RequestAuthToken(); diff --git a/PlexRequests.UI/Views/Admin/Settings.cshtml b/PlexRequests.UI/Views/Admin/Settings.cshtml index 423b98502..91532b433 100644 --- a/PlexRequests.UI/Views/Admin/Settings.cshtml +++ b/PlexRequests.UI/Views/Admin/Settings.cshtml @@ -228,7 +228,7 @@

A comma separated list of users whose requests do not require approval.

- +
From 901f5efb716e8df63e0f58852020f63d14768d0d Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 13:52:06 +0100 Subject: [PATCH 19/46] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0153cfb7a..d5b424b76 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ I wanted to write a similar application in .Net! * Headphones integration! * Ability to run with a reverse proxy! -# Preview () +# Preview ![Preview](http://i.imgur.com/DgwkIsW.gif) From 818c2e80f7d376f6498d63a613b06eab80bf1ec6 Mon Sep 17 00:00:00 2001 From: Drewster727 Date: Wed, 22 Jun 2016 11:27:09 -0500 Subject: [PATCH 20/46] better way of obtaining clean enum string --- .../Notification/EmailMessageNotification.cs | 4 ++-- PlexRequests.Services/Notification/PushbulletNotification.cs | 4 ++-- PlexRequests.Services/Notification/PushoverNotification.cs | 2 +- PlexRequests.Store/RequestedModel.cs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/PlexRequests.Services/Notification/EmailMessageNotification.cs b/PlexRequests.Services/Notification/EmailMessageNotification.cs index 466ff7a24..77b71e58a 100644 --- a/PlexRequests.Services/Notification/EmailMessageNotification.cs +++ b/PlexRequests.Services/Notification/EmailMessageNotification.cs @@ -120,8 +120,8 @@ namespace PlexRequests.Services.Notification { var message = new MimeMessage { - Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has requested the {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}" }, - Subject = $"Plex Requests: New {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} request for {model.Title}!" + Body = new TextPart("plain") { Text = $"Hello! The user '{model.User}' has requested the {model.RequestType.GetString()?.ToLower()} '{model.Title}'! Please log in to approve this request. Request Date: {model.DateTime.ToString("f")}" }, + Subject = $"Plex Requests: New {model.RequestType.GetString()?.ToLower()} request for {model.Title}!" }; message.From.Add(new MailboxAddress(settings.EmailSender, settings.EmailSender)); message.To.Add(new MailboxAddress(settings.RecipientEmail, settings.RecipientEmail)); diff --git a/PlexRequests.Services/Notification/PushbulletNotification.cs b/PlexRequests.Services/Notification/PushbulletNotification.cs index 8eda8d0b9..f6003bf1d 100644 --- a/PlexRequests.Services/Notification/PushbulletNotification.cs +++ b/PlexRequests.Services/Notification/PushbulletNotification.cs @@ -105,8 +105,8 @@ namespace PlexRequests.Services.Notification private async Task PushNewRequestAsync(NotificationModel model, PushbulletNotificationSettings settings) { - var message = $"The {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} '{model.Title}' has been requested by user: {model.User}"; - var pushTitle = $"Plex Requests: The {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} {model.Title} has been requested!"; + var message = $"The {model.RequestType.GetString()?.ToLower()} '{model.Title}' has been requested by user: {model.User}"; + var pushTitle = $"Plex Requests: The {model.RequestType.GetString()?.ToLower()} {model.Title} has been requested!"; await Push(settings, message, pushTitle); } diff --git a/PlexRequests.Services/Notification/PushoverNotification.cs b/PlexRequests.Services/Notification/PushoverNotification.cs index 9831e6562..b259a6faa 100644 --- a/PlexRequests.Services/Notification/PushoverNotification.cs +++ b/PlexRequests.Services/Notification/PushoverNotification.cs @@ -105,7 +105,7 @@ namespace PlexRequests.Services.Notification private async Task PushNewRequestAsync(NotificationModel model, PushoverNotificationSettings settings) { - var message = $"Plex Requests: The {RequestTypeDisplay.Get(model.RequestType)?.ToLower()} '{model.Title}' has been requested by user: {model.User}"; + var message = $"Plex Requests: The {model.RequestType.GetString()?.ToLower()} '{model.Title}' has been requested by user: {model.User}"; await Push(settings, message); } diff --git a/PlexRequests.Store/RequestedModel.cs b/PlexRequests.Store/RequestedModel.cs index 254b4f7be..b203db7d3 100644 --- a/PlexRequests.Store/RequestedModel.cs +++ b/PlexRequests.Store/RequestedModel.cs @@ -80,7 +80,7 @@ namespace PlexRequests.Store public static class RequestTypeDisplay { - public static string Get(RequestType type) + public static string GetString(this RequestType type) { switch (type) { From 752915ea0a2dbeac9fc0da4e5ef782cbab988fda Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 20:22:38 +0100 Subject: [PATCH 21/46] Potential fix for #350 --- PlexRequests.Services/Jobs/CouchPotatoCacher.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs index 3fb831b12..8a9f666b1 100644 --- a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs +++ b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs @@ -87,7 +87,12 @@ namespace PlexRequests.Services.Jobs public int[] QueuedIds() { var movies = Cache.Get(CacheKeys.CouchPotatoQueued); - return movies?.movies?.Select(x => x.info.tmdb_id).ToArray() ?? new int[] { }; + var items = movies?.movies?.Select(x => x.info?.tmdb_id).Cast().ToArray(); + if (items == null) + { + return new int[] { }; + } + return items; } public void Execute(IJobExecutionContext context) From 0b1edcc488956a7efd1a679d66d7ceb0057719c2 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 20:33:24 +0100 Subject: [PATCH 22/46] Slight changes, moved the donate button --- .../Jobs/CouchPotatoCacher.cs | 6 +- PlexRequests.UI/Views/Shared/_Layout.cshtml | 314 +++++++++--------- 2 files changed, 159 insertions(+), 161 deletions(-) diff --git a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs index 8a9f666b1..471965842 100644 --- a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs +++ b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs @@ -88,11 +88,7 @@ namespace PlexRequests.Services.Jobs { var movies = Cache.Get(CacheKeys.CouchPotatoQueued); var items = movies?.movies?.Select(x => x.info?.tmdb_id).Cast().ToArray(); - if (items == null) - { - return new int[] { }; - } - return items; + return items ?? new int[] { }; } public void Execute(IJobExecutionContext context) diff --git a/PlexRequests.UI/Views/Shared/_Layout.cshtml b/PlexRequests.UI/Views/Shared/_Layout.cshtml index fee4537f8..b108cf6ce 100644 --- a/PlexRequests.UI/Views/Shared/_Layout.cshtml +++ b/PlexRequests.UI/Views/Shared/_Layout.cshtml @@ -1,157 +1,159 @@ -@using Nancy.Security -@using Nancy.Session -@using PlexRequests.UI.Helpers -@using PlexRequests.UI.Models -@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase -@{ - var baseUrl = Html.GetBaseUrl(); - var url = string.Empty; - if (!string.IsNullOrEmpty(baseUrl.ToHtmlString())) - { - url = "/" + baseUrl.ToHtmlString(); - } -} - - - - Plex Requests - - - @Html.LoadAnalytics() - @Html.LoadAssets() - - - - - - -
- @RenderBody() -
-
- - - -
- - - \ No newline at end of file From af9953be6cf280ecf4cec08048f145b03ed4f9b7 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 21:49:50 +0100 Subject: [PATCH 23/46] Added logging #350 --- PlexRequests.Services/Jobs/CouchPotatoCacher.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs index 471965842..ee93513ab 100644 --- a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs +++ b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs @@ -86,7 +86,12 @@ namespace PlexRequests.Services.Jobs // we do not want to set here... public int[] QueuedIds() { + Log.Error("This is not an error, starting to get the CP Cached Id's"); + var movies = Cache.Get(CacheKeys.CouchPotatoQueued); + Log.Error("Cached result:"); + Log.Error(movies.DumpJson()); + var items = movies?.movies?.Select(x => x.info?.tmdb_id).Cast().ToArray(); return items ?? new int[] { }; } From 8b52ba29679bcb0a602d4c057ed416c61a196cef Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 22 Jun 2016 22:21:25 +0100 Subject: [PATCH 24/46] Generic try catch to fix #350 --- .../Jobs/CouchPotatoCacher.cs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs index ee93513ab..be36d004f 100644 --- a/PlexRequests.Services/Jobs/CouchPotatoCacher.cs +++ b/PlexRequests.Services/Jobs/CouchPotatoCacher.cs @@ -24,6 +24,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion + +using System; using System.Linq; using NLog; @@ -86,14 +88,18 @@ namespace PlexRequests.Services.Jobs // we do not want to set here... public int[] QueuedIds() { - Log.Error("This is not an error, starting to get the CP Cached Id's"); + try + { + var movies = Cache.Get(CacheKeys.CouchPotatoQueued); - var movies = Cache.Get(CacheKeys.CouchPotatoQueued); - Log.Error("Cached result:"); - Log.Error(movies.DumpJson()); - - var items = movies?.movies?.Select(x => x.info?.tmdb_id).Cast().ToArray(); - return items ?? new int[] { }; + var items = movies?.movies?.Select(x => x.info?.tmdb_id).Cast().ToArray(); + return items ?? new int[] { }; + } + catch (Exception e) + { + Log.Error(e); + return new int[] {}; + } } public void Execute(IJobExecutionContext context) From 4a79bb782e6fa11ee58a8b2d71ecde5912d5075a Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 23 Jun 2016 08:50:34 +0100 Subject: [PATCH 25/46] Fixed #362 --- PlexRequests.UI/Views/Issues/Index.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlexRequests.UI/Views/Issues/Index.cshtml b/PlexRequests.UI/Views/Issues/Index.cshtml index 77d7b983f..acd721b3d 100644 --- a/PlexRequests.UI/Views/Issues/Index.cshtml +++ b/PlexRequests.UI/Views/Issues/Index.cshtml @@ -26,7 +26,7 @@

Type

-

Issue's

+

Issues

From d8cca4a971f48ce317d791468fcfaecb73b8b603 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 23 Jun 2016 09:01:05 +0100 Subject: [PATCH 26/46] Some more useful analytical information --- PlexRequests.Helpers/Analytics/Action.cs | 6 +++++- PlexRequests.UI/Modules/SearchModule.cs | 22 +++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/PlexRequests.Helpers/Analytics/Action.cs b/PlexRequests.Helpers/Analytics/Action.cs index 4a42a45be..6cbe2a737 100644 --- a/PlexRequests.Helpers/Analytics/Action.cs +++ b/PlexRequests.Helpers/Analytics/Action.cs @@ -35,6 +35,10 @@ namespace PlexRequests.Helpers.Analytics Save, Update, Start, - View + View, + Movie, + TvShow, + Album, + Request } } \ No newline at end of file diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index f02a417ea..ddb9f31e1 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -53,11 +53,14 @@ using Nancy.Responses; using PlexRequests.Api.Models.Tv; using PlexRequests.Core.Models; +using PlexRequests.Helpers.Analytics; using PlexRequests.Store.Models; using PlexRequests.Store.Repository; using TMDbLib.Objects.General; +using Action = PlexRequests.Helpers.Analytics.Action; + namespace PlexRequests.UI.Modules { public class SearchModule : BaseAuthModule @@ -69,7 +72,7 @@ namespace PlexRequests.UI.Modules INotificationService notify, IMusicBrainzApi mbApi, IHeadphonesApi hpApi, ISettingsService hpService, ICouchPotatoCacher cpCacher, ISonarrCacher sonarrCacher, ISickRageCacher sickRageCacher, IPlexApi plexApi, ISettingsService plexService, ISettingsService auth, IRepository u, ISettingsService email, - IIssueService issue) : base("search", prSettings) + IIssueService issue, IAnalytics a) : base("search", prSettings) { Auth = auth; PlexService = plexService; @@ -95,6 +98,7 @@ namespace PlexRequests.UI.Modules UsersToNotifyRepo = u; EmailNotificationSettings = email; IssueService = issue; + Analytics = a; Get["/", true] = async (x, ct) => await RequestLoad(); @@ -140,31 +144,31 @@ namespace PlexRequests.UI.Modules private IHeadphonesApi HeadphonesApi { get; } private IRepository UsersToNotifyRepo { get; } private IIssueService IssueService { get; } + private IAnalytics Analytics { get; } private static Logger Log = LogManager.GetCurrentClassLogger(); private async Task RequestLoad() { var settings = await PrService.GetSettingsAsync(); - Log.Trace("Loading Index"); return View["Search/Index", settings]; } private async Task UpcomingMovies() { - Log.Trace("Loading upcoming movies"); + await Analytics.TrackEventAsync(Category.Search, Action.Movie, "Upcoming", Username, CookieHelper.GetAnalyticClientId(Cookies)); return await ProcessMovies(MovieSearchType.Upcoming, string.Empty); } private async Task CurrentlyPlayingMovies() { - Log.Trace("Loading currently playing movies"); + await Analytics.TrackEventAsync(Category.Search, Action.Movie, "CurrentlyPlaying", Username, CookieHelper.GetAnalyticClientId(Cookies)); return await ProcessMovies(MovieSearchType.CurrentlyPlaying, string.Empty); } private async Task SearchMovie(string searchTerm) { - Log.Trace("Searching for Movie {0}", searchTerm); + await Analytics.TrackEventAsync(Category.Search, Action.Movie, searchTerm, Username, CookieHelper.GetAnalyticClientId(Cookies)); return await ProcessMovies(MovieSearchType.Search, searchTerm); } @@ -279,6 +283,7 @@ namespace PlexRequests.UI.Modules private async Task SearchTvShow(string searchTerm) { + await Analytics.TrackEventAsync(Category.Search, Action.TvShow, searchTerm, Username, CookieHelper.GetAnalyticClientId(Cookies)); var plexSettings = await PlexService.GetSettingsAsync(); Log.Trace("Searching for TV Show {0}", searchTerm); @@ -366,6 +371,7 @@ namespace PlexRequests.UI.Modules private async Task SearchMusic(string searchTerm) { + await Analytics.TrackEventAsync(Category.Search, Action.Album, searchTerm, Username, CookieHelper.GetAnalyticClientId(Cookies)); var apiAlbums = new List(); await Task.Run(() => MusicBrainzApi.SearchAlbum(searchTerm)).ContinueWith((t) => { @@ -417,6 +423,7 @@ namespace PlexRequests.UI.Modules private async Task RequestMovie(int movieId) { + await Analytics.TrackEventAsync(Category.Search, Action.Request, "Movie", Username, CookieHelper.GetAnalyticClientId(Cookies)); var movieInfo = MovieApi.GetMovieInformation(movieId).Result; var fullMovieName = $"{movieInfo.Title}{(movieInfo.ReleaseDate.HasValue ? $" ({movieInfo.ReleaseDate.Value.Year})" : string.Empty)}"; Log.Trace("Getting movie info from TheMovieDb"); @@ -559,6 +566,7 @@ namespace PlexRequests.UI.Modules /// private async Task RequestTvShow(int showId, string seasons) { + await Analytics.TrackEventAsync(Category.Search, Action.Request, "TvShow", Username, CookieHelper.GetAnalyticClientId(Cookies)); var tvApi = new TvMazeApi(); var showInfo = tvApi.ShowLookupByTheTvDbId(showId); @@ -762,6 +770,7 @@ namespace PlexRequests.UI.Modules private async Task RequestAlbum(string releaseId) { + await Analytics.TrackEventAsync(Category.Search, Action.Request, "Album", Username, CookieHelper.GetAnalyticClientId(Cookies)); var settings = await PrService.GetSettingsAsync(); var existingRequest = await RequestService.CheckRequestAsync(releaseId); Log.Debug("Checking for an existing request"); @@ -919,6 +928,7 @@ namespace PlexRequests.UI.Modules private async Task NotifyUser(bool notify) { + await Analytics.TrackEventAsync(Category.Search, Action.Save, "NotifyUser", Username, CookieHelper.GetAnalyticClientId(Cookies), notify ? 1 : 0); var authSettings = await Auth.GetSettingsAsync(); var auth = authSettings.UserAuthentication; var emailSettings = await EmailNotificationSettings.GetSettingsAsync(); @@ -984,7 +994,5 @@ namespace PlexRequests.UI.Modules var model = seasons.Select(x => x.number); return Response.AsJson(model); } - - } } From ba52772fd95b32b0c73ff53a59c312df4ad9b6df Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 23 Jun 2016 14:39:04 +0100 Subject: [PATCH 27/46] Fixed #364 --- PlexRequests.UI/Content/requests-1.7.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlexRequests.UI/Content/requests-1.7.js b/PlexRequests.UI/Content/requests-1.7.js index 041b67bcc..a65bc3425 100644 --- a/PlexRequests.UI/Content/requests-1.7.js +++ b/PlexRequests.UI/Content/requests-1.7.js @@ -159,7 +159,7 @@ $('#approveTVShows').click(function (e) { $('#deleteMovies').click(function (e) { e.preventDefault(); - if (!confirm("Are you sure you want to delete all TV show requests?")) return; + if (!confirm("Are you sure you want to delete all Movie requests?")) return; var buttonId = e.target.id; var origHtml = $(this).html(); From 7a8d7e3f19d5a5c1370e782e9c17d73b485000c5 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 24 Jun 2016 09:39:31 +0100 Subject: [PATCH 28/46] Started #243 --- PlexRequests.Core.Tests/app.config | 22 +- PlexRequests.Core/PlexRequests.Core.csproj | 266 ++-- PlexRequests.Core/app.config | 22 +- PlexRequests.Core/packages.config | 16 +- .../PlexRequests.Resources.csproj | 64 + .../Properties/AssemblyInfo.cs | 36 + PlexRequests.Resources/UI.Designer.cs | 145 ++ PlexRequests.Resources/UI.resx | 128 ++ PlexRequests.Services.Tests/app.config | 22 +- PlexRequests.Services/app.config | 22 +- PlexRequests.UI.Tests/app.config | 54 +- PlexRequests.UI/Bootstrapper.cs | 454 +++--- PlexRequests.UI/Modules/LandingPageModule.cs | 1 + PlexRequests.UI/PlexRequests.UI.csproj | 1314 +++++++++-------- PlexRequests.UI/Startup.cs | 116 +- PlexRequests.UI/Views/UserLogin/Index.cshtml | 138 +- PlexRequests.UI/app.config | 100 +- PlexRequests.sln | 210 +-- 18 files changed, 1757 insertions(+), 1373 deletions(-) create mode 100644 PlexRequests.Resources/PlexRequests.Resources.csproj create mode 100644 PlexRequests.Resources/Properties/AssemblyInfo.cs create mode 100644 PlexRequests.Resources/UI.Designer.cs create mode 100644 PlexRequests.Resources/UI.resx diff --git a/PlexRequests.Core.Tests/app.config b/PlexRequests.Core.Tests/app.config index 44b249bff..afa1b4c43 100644 --- a/PlexRequests.Core.Tests/app.config +++ b/PlexRequests.Core.Tests/app.config @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/PlexRequests.Core/PlexRequests.Core.csproj b/PlexRequests.Core/PlexRequests.Core.csproj index 495a09ed8..555c02754 100644 --- a/PlexRequests.Core/PlexRequests.Core.csproj +++ b/PlexRequests.Core/PlexRequests.Core.csproj @@ -1,134 +1,134 @@ - - - - - Debug - AnyCPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} - Library - Properties - PlexRequests.Core - PlexRequests.Core - v4.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\Assemblies\Mono.Data.Sqlite.dll - - - ..\packages\NLog.4.3.4\lib\net45\NLog.dll - True - - - - - - - - - - - ..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll - - - ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll - - - ..\packages\Nancy.Authentication.Forms.1.4.1\lib\net40\Nancy.Authentication.Forms.dll - - - ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\packages\Octokit.0.19.0\lib\net45\Octokit.dll - - - ..\packages\valueinjecter.3.1.1.2\lib\net40\Omu.ValueInjecter.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {95834072-A675-415D-AA8F-877C91623810} - PlexRequests.Api.Interfaces - - - {CB37A5F8-6DFC-4554-99D3-A42B502E4591} - PlexRequests.Api.Models - - - {8CB8D235-2674-442D-9C6A-35FCAEEB160D} - PlexRequests.Api - - - {1252336D-42A3-482A-804C-836E60173DFA} - PlexRequests.Helpers - - - {92433867-2B7B-477B-A566-96C382427525} - PlexRequests.Store - - - - + + + + + Debug + AnyCPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} + Library + Properties + PlexRequests.Core + PlexRequests.Core + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\Assemblies\Mono.Data.Sqlite.dll + + + ..\packages\NLog.4.3.4\lib\net45\NLog.dll + True + + + + + + + + + + + ..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll + + + ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll + + + ..\packages\Nancy.Authentication.Forms.1.4.1\lib\net40\Nancy.Authentication.Forms.dll + + + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Octokit.0.19.0\lib\net45\Octokit.dll + + + ..\packages\valueinjecter.3.1.1.2\lib\net40\Omu.ValueInjecter.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {95834072-A675-415D-AA8F-877C91623810} + PlexRequests.Api.Interfaces + + + {CB37A5F8-6DFC-4554-99D3-A42B502E4591} + PlexRequests.Api.Models + + + {8CB8D235-2674-442D-9C6A-35FCAEEB160D} + PlexRequests.Api + + + {1252336D-42A3-482A-804C-836E60173DFA} + PlexRequests.Helpers + + + {92433867-2B7B-477B-A566-96C382427525} + PlexRequests.Store + + + + \ No newline at end of file diff --git a/PlexRequests.Core/app.config b/PlexRequests.Core/app.config index 44b249bff..afa1b4c43 100644 --- a/PlexRequests.Core/app.config +++ b/PlexRequests.Core/app.config @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/PlexRequests.Core/packages.config b/PlexRequests.Core/packages.config index 41cff5672..9f54b7236 100644 --- a/PlexRequests.Core/packages.config +++ b/PlexRequests.Core/packages.config @@ -1,9 +1,9 @@ - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.Resources/PlexRequests.Resources.csproj b/PlexRequests.Resources/PlexRequests.Resources.csproj new file mode 100644 index 000000000..4499431cf --- /dev/null +++ b/PlexRequests.Resources/PlexRequests.Resources.csproj @@ -0,0 +1,64 @@ + + + + + Debug + AnyCPU + {9C266462-BE82-461A-87A2-9EDCFB95D732} + Library + Properties + PlexRequests.Resources + PlexRequests.Resources + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + True + True + UI.resx + + + + + PublicResXFileCodeGenerator + UI.Designer.cs + + + + + \ No newline at end of file diff --git a/PlexRequests.Resources/Properties/AssemblyInfo.cs b/PlexRequests.Resources/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..1f1c2d1b7 --- /dev/null +++ b/PlexRequests.Resources/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PlexRequests.Resources")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PlexRequests.Resources")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9c266462-be82-461a-87a2-9edcfb95d732")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PlexRequests.Resources/UI.Designer.cs b/PlexRequests.Resources/UI.Designer.cs new file mode 100644 index 000000000..3e5b37d5f --- /dev/null +++ b/PlexRequests.Resources/UI.Designer.cs @@ -0,0 +1,145 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace PlexRequests.Resources { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class UI { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal UI() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PlexRequests.Resources.UI", typeof(UI).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Something went wrong!. + /// + public static string Javascript_SomethingWentWrong { + get { + return ResourceManager.GetString("Javascript_SomethingWentWrong", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Success!. + /// + public static string Javascript_Success { + get { + return ResourceManager.GetString("Javascript_Success", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Want to watch a movie or tv show but it's not currently on Plex? + /// Login below with your Plex.tv username and password!. + /// + public static string UserLogin_Paragraph { + get { + return ResourceManager.GetString("UserLogin_Paragraph", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your login details are only used to authenticate your Plex account.. + /// + public static string UserLogin_Paragraph_SpanHover { + get { + return ResourceManager.GetString("UserLogin_Paragraph_SpanHover", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password. + /// + public static string UserLogin_Password { + get { + return ResourceManager.GetString("UserLogin_Password", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sign In. + /// + public static string UserLogin_SignIn { + get { + return ResourceManager.GetString("UserLogin_SignIn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Login. + /// + public static string UserLogin_Title { + get { + return ResourceManager.GetString("UserLogin_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Plex.tv Username . + /// + public static string UserLogin_Username { + get { + return ResourceManager.GetString("UserLogin_Username", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Username. + /// + public static string UserLogin_Username_Placeholder { + get { + return ResourceManager.GetString("UserLogin_Username_Placeholder", resourceCulture); + } + } + } +} diff --git a/PlexRequests.Resources/UI.resx b/PlexRequests.Resources/UI.resx new file mode 100644 index 000000000..7d6650fbb --- /dev/null +++ b/PlexRequests.Resources/UI.resx @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Login + + + Want to watch a movie or tv show but it's not currently on Plex? + Login below with your Plex.tv username and password! + + + Your login details are only used to authenticate your Plex account. + + + Plex.tv Username + + + Username + + + Password + + + Sign In + + + Something went wrong! + + + Success! + + \ No newline at end of file diff --git a/PlexRequests.Services.Tests/app.config b/PlexRequests.Services.Tests/app.config index 44b249bff..afa1b4c43 100644 --- a/PlexRequests.Services.Tests/app.config +++ b/PlexRequests.Services.Tests/app.config @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/PlexRequests.Services/app.config b/PlexRequests.Services/app.config index 44b249bff..afa1b4c43 100644 --- a/PlexRequests.Services/app.config +++ b/PlexRequests.Services/app.config @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/PlexRequests.UI.Tests/app.config b/PlexRequests.UI.Tests/app.config index d1c064e34..3799f3a1a 100644 --- a/PlexRequests.UI.Tests/app.config +++ b/PlexRequests.UI.Tests/app.config @@ -1,28 +1,28 @@ - - - - -
- - - - - - - - - - - - - - - - - - - - - - + + + + +
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index 176404b02..8a1df5539 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -1,228 +1,228 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: Bootstrapper.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.Net; - -using Mono.Data.Sqlite; - -using Nancy; -using Nancy.Authentication.Forms; -using Nancy.Bootstrapper; -using Nancy.Conventions; -using Nancy.Cryptography; -using Nancy.Diagnostics; -using Nancy.Session; -using Nancy.TinyIoc; - -using PlexRequests.Api; -using PlexRequests.Api.Interfaces; -using PlexRequests.Core; -using PlexRequests.Core.SettingModels; -using PlexRequests.Helpers; -using PlexRequests.Services; -using PlexRequests.Services.Interfaces; -using PlexRequests.Services.Notification; -using PlexRequests.Store; -using PlexRequests.Store.Models; -using PlexRequests.Store.Repository; -using PlexRequests.UI.Helpers; -using Nancy.Json; - -using PlexRequests.Helpers.Analytics; -using PlexRequests.Services.Jobs; -using PlexRequests.UI.Jobs; - -using Quartz; -using Quartz.Impl; -using Quartz.Spi; - -namespace PlexRequests.UI -{ - public class Bootstrapper : DefaultNancyBootstrapper - { - // The bootstrapper enables you to reconfigure the composition of the framework, - // by overriding the various methods and properties. - // For more information https://github.com/NancyFx/Nancy/wiki/Bootstrapper - - protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) - { - ConfigureContainer(container); - - JsonSettings.MaxJsonLength = int.MaxValue; - - CookieBasedSessions.Enable(pipelines, CryptographyConfiguration.Default); - StaticConfiguration.DisableErrorTraces = false; - - base.ApplicationStartup(container, pipelines); - - var settings = new SettingsServiceV2(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); - var baseUrl = settings.GetSettings().BaseUrl; - var redirect = string.IsNullOrEmpty(baseUrl) ? "~/login" : $"~/{baseUrl}/login"; - - // Enable forms auth - var formsAuthConfiguration = new FormsAuthenticationConfiguration - { - RedirectUrl = redirect, - UserMapper = container.Resolve() - }; - - FormsAuthentication.Enable(pipelines, formsAuthConfiguration); - - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; - ServicePointManager.ServerCertificateValidationCallback += - (sender, certificate, chain, sslPolicyErrors) => true; - - SubscribeAllObservers(container); - - } - - protected override void ConfigureConventions(NancyConventions nancyConventions) - { - base.ConfigureConventions(nancyConventions); - - var settings = new SettingsServiceV2(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); - var assetLocation = settings.GetSettings().BaseUrl; - nancyConventions.StaticContentsConventions.Add( - StaticContentConventionBuilder.AddDirectory($"{assetLocation}/Content", "Content") - ); - - nancyConventions.StaticContentsConventions.AddDirectory($"{assetLocation}/docs", "swagger-ui"); - } - - protected override DiagnosticsConfiguration DiagnosticsConfiguration => new DiagnosticsConfiguration { Password = @"password" }; - - private void SubscribeAllObservers(TinyIoCContainer container) - { - var notificationService = container.Resolve(); - - var emailSettingsService = container.Resolve>(); - var emailSettings = emailSettingsService.GetSettings(); - if (emailSettings.Enabled) - { - notificationService.Subscribe(new EmailMessageNotification(emailSettingsService)); - } - - var pushbulletService = container.Resolve>(); - var pushbulletSettings = pushbulletService.GetSettings(); - if (pushbulletSettings.Enabled) - { - notificationService.Subscribe(new PushbulletNotification(container.Resolve(), pushbulletService)); - } - - var pushoverService = container.Resolve>(); - var pushoverSettings = pushoverService.GetSettings(); - if (pushoverSettings.Enabled) - { - notificationService.Subscribe(new PushoverNotification(container.Resolve(), pushoverService)); - } - - var slackService = container.Resolve>(); - var slackSettings = slackService.GetSettings(); - if (slackSettings.Enabled) - { - notificationService.Subscribe(new SlackNotification(container.Resolve(), slackService)); - } - } - - protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context) - { - //CORS Enable - pipelines.AfterRequest.AddItemToEndOfPipeline((ctx) => - { - ctx.Response.WithHeader("Access-Control-Allow-Origin", "*") - .WithHeader("Access-Control-Allow-Methods", "POST,GET") - .WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type"); - - }); - base.RequestStartup(container, pipelines, context); - } - - private void ConfigureContainer(TinyIoCContainer container) - { - container.Register().AsSingleton(); - container.Register(new DbConfiguration(new SqliteFactory())); - container.Register, UserRepository>(); - container.Register(); - container.Register(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - - // Notification Service - container.Register().AsSingleton(); - // Settings - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - container.Register, SettingsServiceV2>(); - - // Repo's - container.Register, GenericRepository>(); - container.Register, GenericRepository>(); - container.Register, GenericRepository>(); - container.Register, GenericRepository>(); - container.Register(); - container.Register(); - container.Register(); - container.Register(); - - // Services - container.Register(); - container.Register(); - container.Register(); - container.Register(); - container.Register(); - - container.Register(); - container.Register(); - container.Register(); - - - // Api - container.Register(); - container.Register(); - container.Register(); - container.Register(); - container.Register(); - container.Register(); - container.Register(); - container.Register(); - container.Register(); - - var loc = ServiceLocator.Instance; - loc.SetContainer(container); - } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: Bootstrapper.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.Net; + +using Mono.Data.Sqlite; + +using Nancy; +using Nancy.Authentication.Forms; +using Nancy.Bootstrapper; +using Nancy.Conventions; +using Nancy.Cryptography; +using Nancy.Diagnostics; +using Nancy.Session; +using Nancy.TinyIoc; + +using PlexRequests.Api; +using PlexRequests.Api.Interfaces; +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.Helpers; +using PlexRequests.Services; +using PlexRequests.Services.Interfaces; +using PlexRequests.Services.Notification; +using PlexRequests.Store; +using PlexRequests.Store.Models; +using PlexRequests.Store.Repository; +using PlexRequests.UI.Helpers; +using Nancy.Json; + +using PlexRequests.Helpers.Analytics; +using PlexRequests.Services.Jobs; +using PlexRequests.UI.Jobs; + +using Quartz; +using Quartz.Impl; +using Quartz.Spi; + +namespace PlexRequests.UI +{ + public class Bootstrapper : DefaultNancyBootstrapper + { + // The bootstrapper enables you to reconfigure the composition of the framework, + // by overriding the various methods and properties. + // For more information https://github.com/NancyFx/Nancy/wiki/Bootstrapper + + protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) + { + ConfigureContainer(container); + + JsonSettings.MaxJsonLength = int.MaxValue; + + CookieBasedSessions.Enable(pipelines, CryptographyConfiguration.Default); + StaticConfiguration.DisableErrorTraces = false; + + base.ApplicationStartup(container, pipelines); + + var settings = new SettingsServiceV2(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); + var baseUrl = settings.GetSettings().BaseUrl; + var redirect = string.IsNullOrEmpty(baseUrl) ? "~/login" : $"~/{baseUrl}/login"; + + // Enable forms auth + var formsAuthConfiguration = new FormsAuthenticationConfiguration + { + RedirectUrl = redirect, + UserMapper = container.Resolve() + }; + + FormsAuthentication.Enable(pipelines, formsAuthConfiguration); + + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; + ServicePointManager.ServerCertificateValidationCallback += + (sender, certificate, chain, sslPolicyErrors) => true; + + SubscribeAllObservers(container); + + } + + protected override void ConfigureConventions(NancyConventions nancyConventions) + { + base.ConfigureConventions(nancyConventions); + + var settings = new SettingsServiceV2(new SettingsJsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); + var assetLocation = settings.GetSettings().BaseUrl; + nancyConventions.StaticContentsConventions.Add( + StaticContentConventionBuilder.AddDirectory($"{assetLocation}/Content", "Content") + ); + + nancyConventions.StaticContentsConventions.AddDirectory($"{assetLocation}/docs", "swagger-ui"); + } + + protected override DiagnosticsConfiguration DiagnosticsConfiguration => new DiagnosticsConfiguration { Password = @"password" }; + + private void SubscribeAllObservers(TinyIoCContainer container) + { + var notificationService = container.Resolve(); + + var emailSettingsService = container.Resolve>(); + var emailSettings = emailSettingsService.GetSettings(); + if (emailSettings.Enabled) + { + notificationService.Subscribe(new EmailMessageNotification(emailSettingsService)); + } + + var pushbulletService = container.Resolve>(); + var pushbulletSettings = pushbulletService.GetSettings(); + if (pushbulletSettings.Enabled) + { + notificationService.Subscribe(new PushbulletNotification(container.Resolve(), pushbulletService)); + } + + var pushoverService = container.Resolve>(); + var pushoverSettings = pushoverService.GetSettings(); + if (pushoverSettings.Enabled) + { + notificationService.Subscribe(new PushoverNotification(container.Resolve(), pushoverService)); + } + + var slackService = container.Resolve>(); + var slackSettings = slackService.GetSettings(); + if (slackSettings.Enabled) + { + notificationService.Subscribe(new SlackNotification(container.Resolve(), slackService)); + } + } + + protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context) + { + //CORS Enable + pipelines.AfterRequest.AddItemToEndOfPipeline((ctx) => + { + ctx.Response.WithHeader("Access-Control-Allow-Origin", "*") + .WithHeader("Access-Control-Allow-Methods", "POST,GET") + .WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type"); + + }); + base.RequestStartup(container, pipelines, context); + } + + private void ConfigureContainer(TinyIoCContainer container) + { + container.Register().AsSingleton(); + container.Register(new DbConfiguration(new SqliteFactory())); + container.Register, UserRepository>(); + container.Register(); + container.Register(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + + // Notification Service + container.Register().AsSingleton(); + // Settings + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); + + // Repo's + container.Register, GenericRepository>(); + container.Register, GenericRepository>(); + container.Register, GenericRepository>(); + container.Register, GenericRepository>(); + container.Register(); + container.Register(); + container.Register(); + container.Register(); + + // Services + container.Register(); + container.Register(); + container.Register(); + container.Register(); + container.Register(); + + container.Register(); + container.Register(); + container.Register(); + + + // Api + container.Register(); + container.Register(); + container.Register(); + container.Register(); + container.Register(); + container.Register(); + container.Register(); + container.Register(); + container.Register(); + + var loc = ServiceLocator.Instance; + loc.SetContainer(container); + } + } } \ No newline at end of file diff --git a/PlexRequests.UI/Modules/LandingPageModule.cs b/PlexRequests.UI/Modules/LandingPageModule.cs index 4564e32ef..9468662e6 100644 --- a/PlexRequests.UI/Modules/LandingPageModule.cs +++ b/PlexRequests.UI/Modules/LandingPageModule.cs @@ -58,6 +58,7 @@ namespace PlexRequests.UI.Modules private async Task Index() { + var s = await LandingSettings.GetSettingsAsync(); var model = new LandingPageViewModel { diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index 99b5f8641..c5681a18d 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -1,656 +1,660 @@ - - - - - Debug - AnyCPU - {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6} - Exe - Properties - PlexRequests.UI - PlexRequests - v4.5 - 512 - ..\..\ - true - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll - True - - - ..\packages\Nancy.Metadata.Modules.1.4.1\lib\net40\Nancy.Metadata.Modules.dll - True - - - ..\packages\Nancy.Swagger.0.1.0-alpha3\lib\net40\Nancy.Swagger.dll - True - - - ..\packages\NLog.4.3.4\lib\net45\NLog.dll - True - - - ..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll - True - - - ..\packages\Swagger.ObjectModel.0.1.0-alpha3\lib\net40\Swagger.ObjectModel.dll - True - - - - - - - - - - - - ..\packages\CommandLineParser.2.0.275-beta\lib\net45\CommandLine.dll - - - ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll - - - ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll - - - ..\packages\Dapper.1.42\lib\net45\Dapper.dll - - - ..\packages\FluentValidation.6.2.1.0\lib\Net45\FluentValidation.dll - - - ..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll - - - ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll - - - ..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll - - - ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll - - - ..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll - - - ..\Assemblies\Mono.Data.Sqlite.dll - - - ..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll - - - ..\packages\Nancy.Authentication.Basic.1.4.1\lib\net40\Nancy.Authentication.Basic.dll - - - ..\packages\Nancy.Authentication.Forms.1.4.1\lib\net40\Nancy.Authentication.Forms.dll - - - ..\packages\Nancy.Hosting.Self.1.4.1\lib\net40\Nancy.Hosting.Self.dll - - - ..\packages\Nancy.Owin.1.4.1\lib\net40\Nancy.Owin.dll - - - ..\packages\Nancy.Validation.FluentValidation.1.4.1\lib\net40\Nancy.Validation.FluentValidation.dll - - - ..\packages\Nancy.Viewengines.Razor.1.4.1\lib\net40\Nancy.ViewEngines.Razor.dll - - - ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - - - ..\packages\Owin.1.0\lib\net40\Owin.dll - - - ..\packages\Quartz.2.3.3\lib\net40\Quartz.dll - - - ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll - - - ..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - base.scss - PreserveNewest - - - base.css - PreserveNewest - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - datepicker.scss - - - datepicker.css - Always - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - original.scss - PreserveNewest - - - original.css - PreserveNewest - - - plex.scss - PreserveNewest - - - plex.css - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - - PreserveNewest - - - PreserveNewest - - - Always - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - moment.min.js - - - moment.min.es5.js - - - Always - - - pace.scss - - - pace.css - Always - - - PreserveNewest - - - PreserveNewest - - - - - Always - - - - compilerconfig.json - - - PreserveNewest - - - - - - - Always - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - Designer - - - Designer - - - Always - - - Designer - - - Always - - - Always - - - Always - - - Always - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - Always - - - web.config - - - web.config - - - - - - {95834072-A675-415D-AA8F-877C91623810} - PlexRequests.Api.Interfaces - - - {CB37A5F8-6DFC-4554-99D3-A42B502E4591} - PlexRequests.Api.Models - - - {8CB8D235-2674-442D-9C6A-35FCAEEB160D} - PlexRequests.Api - - - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} - PlexRequests.Core - - - {1252336D-42A3-482A-804C-836E60173DFA} - PlexRequests.Helpers - - - {566EFA49-68F8-4716-9693-A6B3F2624DEA} - PlexRequests.Services - - - {92433867-2B7B-477B-A566-96C382427525} - PlexRequests.Store - - - {ebe6fc1c-7b4b-47e9-af54-0ee0604a2be5} - PlexRequests.Updater - - - - - PreserveNewest - - - - - False - Microsoft .NET Framework 4.5.2 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6} + Exe + Properties + PlexRequests.UI + PlexRequests + v4.5 + 512 + ..\..\ + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Nancy.1.4.3\lib\net40\Nancy.dll + True + + + ..\packages\Nancy.Metadata.Modules.1.4.1\lib\net40\Nancy.Metadata.Modules.dll + True + + + ..\packages\Nancy.Swagger.0.1.0-alpha3\lib\net40\Nancy.Swagger.dll + True + + + ..\packages\NLog.4.3.4\lib\net45\NLog.dll + True + + + ..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll + True + + + ..\packages\Swagger.ObjectModel.0.1.0-alpha3\lib\net40\Swagger.ObjectModel.dll + True + + + + + + + + + + + + ..\packages\CommandLineParser.2.0.275-beta\lib\net45\CommandLine.dll + + + ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll + + + ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll + + + ..\packages\Dapper.1.42\lib\net45\Dapper.dll + + + ..\packages\FluentValidation.6.2.1.0\lib\Net45\FluentValidation.dll + + + ..\packages\MarkdownSharp.1.13.0.0\lib\35\MarkdownSharp.dll + + + ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + + + ..\packages\Microsoft.Owin.Host.HttpListener.3.0.1\lib\net45\Microsoft.Owin.Host.HttpListener.dll + + + ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll + + + ..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll + + + ..\Assemblies\Mono.Data.Sqlite.dll + + + ..\packages\Mono.Posix.4.0.0.0\lib\net40\Mono.Posix.dll + + + ..\packages\Nancy.Authentication.Basic.1.4.1\lib\net40\Nancy.Authentication.Basic.dll + + + ..\packages\Nancy.Authentication.Forms.1.4.1\lib\net40\Nancy.Authentication.Forms.dll + + + ..\packages\Nancy.Hosting.Self.1.4.1\lib\net40\Nancy.Hosting.Self.dll + + + ..\packages\Nancy.Owin.1.4.1\lib\net40\Nancy.Owin.dll + + + ..\packages\Nancy.Validation.FluentValidation.1.4.1\lib\net40\Nancy.Validation.FluentValidation.dll + + + ..\packages\Nancy.Viewengines.Razor.1.4.1\lib\net40\Nancy.ViewEngines.Razor.dll + + + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Owin.1.0\lib\net40\Owin.dll + + + ..\packages\Quartz.2.3.3\lib\net40\Quartz.dll + + + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll + + + ..\packages\TMDbLib.0.9.0.0-alpha\lib\net45\TMDbLib.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + base.scss + PreserveNewest + + + base.css + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + datepicker.scss + + + datepicker.css + Always + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + original.scss + PreserveNewest + + + original.css + PreserveNewest + + + plex.scss + PreserveNewest + + + plex.css + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + PreserveNewest + + + PreserveNewest + + + Always + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + moment.min.js + + + moment.min.es5.js + + + Always + + + pace.scss + + + pace.css + Always + + + PreserveNewest + + + PreserveNewest + + + + + Always + + + + compilerconfig.json + + + PreserveNewest + + + + + + + Always + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + PreserveNewest + + + Designer + + + Designer + + + Always + + + Designer + + + Always + + + Always + + + Always + + + Always + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + web.config + + + web.config + + + + + + {95834072-A675-415D-AA8F-877C91623810} + PlexRequests.Api.Interfaces + + + {CB37A5F8-6DFC-4554-99D3-A42B502E4591} + PlexRequests.Api.Models + + + {8CB8D235-2674-442D-9C6A-35FCAEEB160D} + PlexRequests.Api + + + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} + PlexRequests.Core + + + {1252336D-42A3-482A-804C-836E60173DFA} + PlexRequests.Helpers + + + {9c266462-be82-461a-87a2-9edcfb95d732} + PlexRequests.Resources + + + {566EFA49-68F8-4716-9693-A6B3F2624DEA} + PlexRequests.Services + + + {92433867-2B7B-477B-A566-96C382427525} + PlexRequests.Store + + + {ebe6fc1c-7b4b-47e9-af54-0ee0604a2be5} + PlexRequests.Updater + + + + + PreserveNewest + + + + + False + Microsoft .NET Framework 4.5.2 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.UI/Startup.cs b/PlexRequests.UI/Startup.cs index 14aa38657..6f7f5fd8c 100644 --- a/PlexRequests.UI/Startup.cs +++ b/PlexRequests.UI/Startup.cs @@ -1,59 +1,59 @@ -#region Copyright -// /************************************************************************ -// Copyright (c) 2016 Jamie Rees -// File: Startup.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; - -using Nancy.TinyIoc; - -using NLog; - -using Owin; - -using PlexRequests.UI.Helpers; -using PlexRequests.UI.Jobs; - -namespace PlexRequests.UI -{ - public class Startup - { - private static readonly Logger Log = LogManager.GetCurrentClassLogger(); - - public void Configuration(IAppBuilder app) - { - try - { - app.UseNancy(); - var scheduler = new Scheduler(); - scheduler.StartScheduler(); - } - catch (Exception exception) - { - Log.Fatal(exception); - throw; - } - } - } +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: Startup.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; + +using Nancy.TinyIoc; + +using NLog; + +using Owin; + +using PlexRequests.UI.Helpers; +using PlexRequests.UI.Jobs; + +namespace PlexRequests.UI +{ + public class Startup + { + private static readonly Logger Log = LogManager.GetCurrentClassLogger(); + + public void Configuration(IAppBuilder app) + { + try + { + app.UseNancy(); + var scheduler = new Scheduler(); + scheduler.StartScheduler(); + } + catch (Exception exception) + { + Log.Fatal(exception); + throw; + } + } + } } \ No newline at end of file diff --git a/PlexRequests.UI/Views/UserLogin/Index.cshtml b/PlexRequests.UI/Views/UserLogin/Index.cshtml index ff2d574ff..92bf86778 100644 --- a/PlexRequests.UI/Views/UserLogin/Index.cshtml +++ b/PlexRequests.UI/Views/UserLogin/Index.cshtml @@ -1,70 +1,70 @@ -@using PlexRequests.UI.Helpers -
-

Login

-
-

- Want to watch a movie or tv show but it's not currently on Plex? - Login below with your Plex.tv username and password! -

-
-
-
-
- -
-
- -
-
-
- @if (Model.UsePassword) - { -
-
- -
-
- -
-
-
- } - - -
-
- - \ No newline at end of file diff --git a/PlexRequests.UI/app.config b/PlexRequests.UI/app.config index 747d7cb7a..1de7c9330 100644 --- a/PlexRequests.UI/app.config +++ b/PlexRequests.UI/app.config @@ -1,50 +1,50 @@ - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PlexRequests.sln b/PlexRequests.sln index 93ac3b1f4..5bad74ef5 100644 --- a/PlexRequests.sln +++ b/PlexRequests.sln @@ -1,102 +1,108 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI", "PlexRequests.UI\PlexRequests.UI.csproj", "{68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Api", "PlexRequests.Api\PlexRequests.Api.csproj", "{8CB8D235-2674-442D-9C6A-35FCAEEB160D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Api.Interfaces", "PlexRequests.Api.Interfaces\PlexRequests.Api.Interfaces.csproj", "{95834072-A675-415D-AA8F-877C91623810}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Core", "PlexRequests.Core\PlexRequests.Core.csproj", "{DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Store", "PlexRequests.Store\PlexRequests.Store.csproj", "{92433867-2B7B-477B-A566-96C382427525}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F4BC839C-B8FF-48BE-B22E-536A0A0A81A5}" - ProjectSection(SolutionItems) = preProject - .travis.yml = .travis.yml - appveyor.yml = appveyor.yml - LICENSE = LICENSE - README.md = README.md - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Helpers", "PlexRequests.Helpers\PlexRequests.Helpers.csproj", "{1252336D-42A3-482A-804C-836E60173DFA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI.Tests", "PlexRequests.UI.Tests\PlexRequests.UI.Tests.csproj", "{A930E2CF-79E2-45F9-B06A-9A719A254CE4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Core.Tests", "PlexRequests.Core.Tests\PlexRequests.Core.Tests.csproj", "{FCFECD5D-47F6-454D-8692-E27A921BE655}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Services", "PlexRequests.Services\PlexRequests.Services.csproj", "{566EFA49-68F8-4716-9693-A6B3F2624DEA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Api.Models", "PlexRequests.Api.Models\PlexRequests.Api.Models.csproj", "{CB37A5F8-6DFC-4554-99D3-A42B502E4591}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Services.Tests", "PlexRequests.Services.Tests\PlexRequests.Services.Tests.csproj", "{EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Updater", "PlexRequests.Updater\PlexRequests.Updater.csproj", "{EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Helpers.Tests", "PlexRequests.Helpers.Tests\PlexRequests.Helpers.Tests.csproj", "{0E6395D3-B074-49E8-898D-0EB99E507E0E}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Release|Any CPU.Build.0 = Release|Any CPU - {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Release|Any CPU.Build.0 = Release|Any CPU - {95834072-A675-415D-AA8F-877C91623810}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {95834072-A675-415D-AA8F-877C91623810}.Debug|Any CPU.Build.0 = Debug|Any CPU - {95834072-A675-415D-AA8F-877C91623810}.Release|Any CPU.ActiveCfg = Release|Any CPU - {95834072-A675-415D-AA8F-877C91623810}.Release|Any CPU.Build.0 = Release|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.Build.0 = Release|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.Build.0 = Debug|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.ActiveCfg = Release|Any CPU - {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.Build.0 = Release|Any CPU - {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.Build.0 = Release|Any CPU - {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.Build.0 = Release|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.Build.0 = Release|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.Build.0 = Release|Any CPU - {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Release|Any CPU.Build.0 = Release|Any CPU - {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Release|Any CPU.Build.0 = Release|Any CPU - {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Release|Any CPU.Build.0 = Release|Any CPU - {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI", "PlexRequests.UI\PlexRequests.UI.csproj", "{68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Api", "PlexRequests.Api\PlexRequests.Api.csproj", "{8CB8D235-2674-442D-9C6A-35FCAEEB160D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Api.Interfaces", "PlexRequests.Api.Interfaces\PlexRequests.Api.Interfaces.csproj", "{95834072-A675-415D-AA8F-877C91623810}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Core", "PlexRequests.Core\PlexRequests.Core.csproj", "{DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Store", "PlexRequests.Store\PlexRequests.Store.csproj", "{92433867-2B7B-477B-A566-96C382427525}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F4BC839C-B8FF-48BE-B22E-536A0A0A81A5}" + ProjectSection(SolutionItems) = preProject + .travis.yml = .travis.yml + appveyor.yml = appveyor.yml + LICENSE = LICENSE + README.md = README.md + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Helpers", "PlexRequests.Helpers\PlexRequests.Helpers.csproj", "{1252336D-42A3-482A-804C-836E60173DFA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI.Tests", "PlexRequests.UI.Tests\PlexRequests.UI.Tests.csproj", "{A930E2CF-79E2-45F9-B06A-9A719A254CE4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Core.Tests", "PlexRequests.Core.Tests\PlexRequests.Core.Tests.csproj", "{FCFECD5D-47F6-454D-8692-E27A921BE655}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Services", "PlexRequests.Services\PlexRequests.Services.csproj", "{566EFA49-68F8-4716-9693-A6B3F2624DEA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Api.Models", "PlexRequests.Api.Models\PlexRequests.Api.Models.csproj", "{CB37A5F8-6DFC-4554-99D3-A42B502E4591}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Services.Tests", "PlexRequests.Services.Tests\PlexRequests.Services.Tests.csproj", "{EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Updater", "PlexRequests.Updater\PlexRequests.Updater.csproj", "{EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Helpers.Tests", "PlexRequests.Helpers.Tests\PlexRequests.Helpers.Tests.csproj", "{0E6395D3-B074-49E8-898D-0EB99E507E0E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Resources", "PlexRequests.Resources\PlexRequests.Resources.csproj", "{9C266462-BE82-461A-87A2-9EDCFB95D732}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68F5F5F3-B8BB-4911-875F-6F00AAE04EA6}.Release|Any CPU.Build.0 = Release|Any CPU + {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CB8D235-2674-442D-9C6A-35FCAEEB160D}.Release|Any CPU.Build.0 = Release|Any CPU + {95834072-A675-415D-AA8F-877C91623810}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {95834072-A675-415D-AA8F-877C91623810}.Debug|Any CPU.Build.0 = Debug|Any CPU + {95834072-A675-415D-AA8F-877C91623810}.Release|Any CPU.ActiveCfg = Release|Any CPU + {95834072-A675-415D-AA8F-877C91623810}.Release|Any CPU.Build.0 = Release|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581}.Release|Any CPU.Build.0 = Release|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92433867-2B7B-477B-A566-96C382427525}.Release|Any CPU.Build.0 = Release|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.Build.0 = Release|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.Build.0 = Release|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.Build.0 = Release|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {566EFA49-68F8-4716-9693-A6B3F2624DEA}.Release|Any CPU.Build.0 = Release|Any CPU + {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB37A5F8-6DFC-4554-99D3-A42B502E4591}.Release|Any CPU.Build.0 = Release|Any CPU + {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EAADB4AC-064F-4D3A-AFF9-64A33131A9A7}.Release|Any CPU.Build.0 = Release|Any CPU + {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBE6FC1C-7B4B-47E9-AF54-0EE0604A2BE5}.Release|Any CPU.Build.0 = Release|Any CPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.Build.0 = Release|Any CPU + {9C266462-BE82-461A-87A2-9EDCFB95D732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C266462-BE82-461A-87A2-9EDCFB95D732}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C266462-BE82-461A-87A2-9EDCFB95D732}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C266462-BE82-461A-87A2-9EDCFB95D732}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal From 2ec27dce902dc424c854894e2f5e92b837787611 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 24 Jun 2016 10:06:03 +0100 Subject: [PATCH 29/46] Implemented the different languages and added the ability to change cultures. #243 --- .../PlexRequests.Resources.csproj | 7 + PlexRequests.Resources/UI.da.resx | 147 ++++++++++++++++++ PlexRequests.Resources/UI.de.resx | 147 ++++++++++++++++++ PlexRequests.Resources/UI.es.resx | 147 ++++++++++++++++++ PlexRequests.Resources/UI.fr.resx | 147 ++++++++++++++++++ PlexRequests.Resources/UI.it.resx | 147 ++++++++++++++++++ PlexRequests.Resources/UI.pt.resx | 147 ++++++++++++++++++ PlexRequests.Resources/UI.sv.resx | 147 ++++++++++++++++++ PlexRequests.UI/Helpers/CultureHelper.cs | 116 ++++++++++++++ PlexRequests.UI/Modules/CultureModule.cs | 63 ++++++++ PlexRequests.UI/PlexRequests.UI.csproj | 2 + 11 files changed, 1217 insertions(+) create mode 100644 PlexRequests.Resources/UI.da.resx create mode 100644 PlexRequests.Resources/UI.de.resx create mode 100644 PlexRequests.Resources/UI.es.resx create mode 100644 PlexRequests.Resources/UI.fr.resx create mode 100644 PlexRequests.Resources/UI.it.resx create mode 100644 PlexRequests.Resources/UI.pt.resx create mode 100644 PlexRequests.Resources/UI.sv.resx create mode 100644 PlexRequests.UI/Helpers/CultureHelper.cs create mode 100644 PlexRequests.UI/Modules/CultureModule.cs diff --git a/PlexRequests.Resources/PlexRequests.Resources.csproj b/PlexRequests.Resources/PlexRequests.Resources.csproj index 4499431cf..2b4d447c8 100644 --- a/PlexRequests.Resources/PlexRequests.Resources.csproj +++ b/PlexRequests.Resources/PlexRequests.Resources.csproj @@ -48,10 +48,17 @@ + + + + + + PublicResXFileCodeGenerator UI.Designer.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Log ind + + + Ønsker du at se en film eller tv-show, men det er i øjeblikket ikke på Plex? Log nedenfor med dit Plex.tv brugernavn og password !! + + + Dine login-oplysninger bruges kun til at godkende din Plex konto.! + + + Plex.tv Brugernavn + + + Brugernavn + + + Adgangskode + + + log på + + + Noget gik galt + + + Fuldført + + \ No newline at end of file diff --git a/PlexRequests.Resources/UI.de.resx b/PlexRequests.Resources/UI.de.resx new file mode 100644 index 000000000..f4a0fb0fc --- /dev/null +++ b/PlexRequests.Resources/UI.de.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Anmelden + + + Möchten Sie einen Film oder eine TV-Show zu sehen, aber es ist derzeit nicht auf Plex? Loggen Sie sich unten mit Ihrem Plex.tv Benutzernamen und Passwort !! + + + Ihre Login-Daten werden verwendet, nur Ihr Plex Konto zu authentifizieren.! + + + Plex.tv Benutzername! + + + Benutzername + + + Passwort + + + Anmelden! + + + Irgendetwas ist falsch gelaufen + + + Erfolg + + \ No newline at end of file diff --git a/PlexRequests.Resources/UI.es.resx b/PlexRequests.Resources/UI.es.resx new file mode 100644 index 000000000..26660b94a --- /dev/null +++ b/PlexRequests.Resources/UI.es.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + INICIAR SESIÓN + + + ¿Quieres ver una película o programa de televisión, pero no es actualmente en Plex? Ingresa abajo con su nombre de usuario y contraseña Plex.tv !! + + + Sus datos de acceso sólo se utilizan para autenticar su cuenta Plex.! + + + Plex.tv nombre de usuario! + + + Username + + + Contraseña + + + Iniciar sesión + + + Algo salió mal. + + + CRÍTICOS + + \ No newline at end of file diff --git a/PlexRequests.Resources/UI.fr.resx b/PlexRequests.Resources/UI.fr.resx new file mode 100644 index 000000000..88c16161d --- /dev/null +++ b/PlexRequests.Resources/UI.fr.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Se connecter + + + Vous voulez regarder un film ou la télévision, mais il est pas actuellement sur Plex? Connectez-vous ci-dessous avec votre nom d'utilisateur et mot de passe Plex.tv! + + + Vos informations de connexion sont uniquement utilisées pour authentifier votre compte Plex. + + + Plex.tv Nom d'utilisateur + + + Nom d’utilisateur + + + Mot de passe + + + Se connecter! + + + Quelque-chose s'est mal passé! + + + Succès + + \ No newline at end of file diff --git a/PlexRequests.Resources/UI.it.resx b/PlexRequests.Resources/UI.it.resx new file mode 100644 index 000000000..29746d173 --- /dev/null +++ b/PlexRequests.Resources/UI.it.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Login + + + Vuoi guardare un film o tv ma non è attualmente in Plex? Effettua il login con il tuo username e la password Plex.tv !! + + + I dati di accesso vengono utilizzati solo per autenticare l&#39;account Plex.! + + + Plex.tv Nome utente! + + + Nome utente + + + Password + + + Accedi! + + + Errore + + + Successo + + \ No newline at end of file diff --git a/PlexRequests.Resources/UI.pt.resx b/PlexRequests.Resources/UI.pt.resx new file mode 100644 index 000000000..a21345cdb --- /dev/null +++ b/PlexRequests.Resources/UI.pt.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Login + + + Quer assistir a um filme ou programa de TV, mas não está atualmente em Plex? Entre abaixo com seu nome de usuário e senha Plex.tv !! + + + Seus dados de login são apenas usados ​​para autenticar sua conta Plex.! + + + Plex.tv usuário! + + + Nome de usuário + + + Senha + + + Assinar em! + + + Alguma coisa saiu errada. + + + Sucesso + + \ No newline at end of file diff --git a/PlexRequests.Resources/UI.sv.resx b/PlexRequests.Resources/UI.sv.resx new file mode 100644 index 000000000..f5ae3b249 --- /dev/null +++ b/PlexRequests.Resources/UI.sv.resx @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Logga in + + + Vill du titta på en film eller TV-show, men det är inte närvarande på Plex? Logga in nedan med Plex.tv användarnamn och lösenord !! + + + Dina inloggningsuppgifter används endast för att autentisera ditt Plex-konto.! + + + Plex.tv användarnamn! + + + Användarnamn + + + Lösenord + + + Logga in! + + + Något gick fel + + + Lyckades + + \ No newline at end of file diff --git a/PlexRequests.UI/Helpers/CultureHelper.cs b/PlexRequests.UI/Helpers/CultureHelper.cs new file mode 100644 index 000000000..e78758585 --- /dev/null +++ b/PlexRequests.UI/Helpers/CultureHelper.cs @@ -0,0 +1,116 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: CultureHelper.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; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace PlexRequests.UI.Helpers +{ + public class CultureHelper + { + private static readonly List ValidCultures = new List { "en-US", "de-DE", "fr-FR", "es-ES", "de", "en", "fr", "es","da","sv","it" }; + + private static readonly List ImplimentedCultures = new List { + "en-US", + "en", + "de", + "fr", + "es", + "da", + "sv", + "it" + }; + + /// + /// Returns true if the language is a right-to-left language. + /// + public static bool IsRighToLeft() + { + return Thread.CurrentThread.CurrentCulture.TextInfo.IsRightToLeft; + } + + /// + /// Returns a valid culture name based on "name" parameter. If "name" is not valid, it returns the default culture "en-US" + /// + /// Culture's name (e.g. en-US) + public static string GetImplementedCulture(string name) + { + if (string.IsNullOrEmpty(name)) + { + return GetDefaultCulture(); + } + + // Validate the culture + if (!ValidCultures.Any(c => c.Equals(name, StringComparison.InvariantCultureIgnoreCase))) + { + return GetDefaultCulture(); + } + + if (ImplimentedCultures.Any(c => c.Equals(name, StringComparison.InvariantCultureIgnoreCase))) + { + return name; // We do have the culture, lets go with it + } + + // Find a close match. + var match = GetNeutralCulture(name); + + foreach (var c in ImplimentedCultures.Where(c => c.StartsWith(match, StringComparison.InvariantCultureIgnoreCase))) + { + return c; + } + + return GetDefaultCulture(); // return Default culture since we cannot find anything + } + + /// + /// Returns default culture name which is the first name declared (e.g. en-US) + /// + /// Culture string e.g. en-US + public static string GetDefaultCulture() + { + return ImplimentedCultures[0]; // return first culture + } + + public static string GetCurrentCulture() + { + return Thread.CurrentThread.CurrentCulture.Name; + } + + public static string GetCurrentNeutralCulture() + { + return GetNeutralCulture(Thread.CurrentThread.CurrentCulture.Name); + } + + public static string GetNeutralCulture(string name) + { + if (!name.Contains("-")) return name; + + return name.Split('-')[0]; // Read first part only + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/Modules/CultureModule.cs b/PlexRequests.UI/Modules/CultureModule.cs new file mode 100644 index 000000000..6ce1b3a11 --- /dev/null +++ b/PlexRequests.UI/Modules/CultureModule.cs @@ -0,0 +1,63 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: CultureModule.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; + +using Nancy; +using Nancy.Extensions; +using Nancy.Responses; + +using PlexRequests.Core; +using PlexRequests.Core.SettingModels; +using PlexRequests.UI.Helpers; + +namespace PlexRequests.UI.Modules +{ + public class CultureModule : BaseModule + { + private const string CookieName = "_culture"; + public CultureModule(ISettingsService pr) : base("culture",pr) + { + Get["/culture"] = x => SetCulture(); + } + + public RedirectResponse SetCulture() + { + var culture = (string)Request.Query["culture"]; + var returnUrl = (string)Request.Query["returnUrl"]; + + // Validate + culture = CultureHelper.GetImplementedCulture(culture); + + var cookie = Request.Cookies["_culture"]; + var response = Context.GetRedirect(returnUrl); + + response.WithCookie(CookieName, cookie ?? culture, DateTime.Now.AddYears(1)); + + return response; + } + } +} \ No newline at end of file diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index c5681a18d..39162d60e 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -159,6 +159,7 @@ + @@ -196,6 +197,7 @@ + From bcdb612faaabb03e76c8109153c22cd7ed70a6ec Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 24 Jun 2016 11:05:03 +0100 Subject: [PATCH 30/46] Added languages #243 --- .../PlexRequests.Resources.csproj | 18 -- PlexRequests.UI/Modules/BaseModule.cs | 46 ++++- PlexRequests.UI/Modules/CultureModule.cs | 17 +- PlexRequests.UI/PlexRequests.UI.csproj | 23 ++- .../Resources}/UI.Designer.cs | 166 +++++++++++++++++- .../Resources}/UI.da.resx | 54 ++++++ .../Resources}/UI.de.resx | 54 ++++++ .../Resources}/UI.es.resx | 54 ++++++ .../Resources}/UI.fr.resx | 54 ++++++ .../Resources}/UI.it.resx | 54 ++++++ .../Resources}/UI.pt.resx | 54 ++++++ .../Resources}/UI.resx | 54 ++++++ .../Resources}/UI.sv.resx | 54 ++++++ PlexRequests.UI/Views/Shared/_Layout.cshtml | 38 ++-- PlexRequests.UI/Views/UserLogin/Index.cshtml | 4 +- PlexRequests.sln | 6 - 16 files changed, 700 insertions(+), 50 deletions(-) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.Designer.cs (50%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.da.resx (80%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.de.resx (79%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.es.resx (79%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.fr.resx (79%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.it.resx (79%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.pt.resx (80%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.resx (76%) rename {PlexRequests.Resources => PlexRequests.UI/Resources}/UI.sv.resx (80%) diff --git a/PlexRequests.Resources/PlexRequests.Resources.csproj b/PlexRequests.Resources/PlexRequests.Resources.csproj index 2b4d447c8..2179f207a 100644 --- a/PlexRequests.Resources/PlexRequests.Resources.csproj +++ b/PlexRequests.Resources/PlexRequests.Resources.csproj @@ -41,24 +41,6 @@ - - True - True - UI.resx - - - - - - - - - - - PublicResXFileCodeGenerator - UI.Designer.cs - - @Html.LoadAnalytics() @@ -32,17 +33,17 @@ - Plex Requests + @UI.Layout_Title
@@ -101,7 +115,7 @@ success: function (response) { if (response.updateAvailable) { var status = createBaseUrl(urlBase, '/admin/status'); - $('#updateAvailable').html(" There is a new update available! Click Here!"); + $('#updateAvailable').html(" @UI.Layout_UpdateAvailablePart1 @UI.Layout_UpdateAvailablePart2"); $('#updateAvailable').removeAttr("hidden"); $('body').addClass('update-available'); } diff --git a/PlexRequests.UI/Views/UserLogin/Index.cshtml b/PlexRequests.UI/Views/UserLogin/Index.cshtml index 92bf86778..0c04b8f7b 100644 --- a/PlexRequests.UI/Views/UserLogin/Index.cshtml +++ b/PlexRequests.UI/Views/UserLogin/Index.cshtml @@ -1,5 +1,5 @@ -@using PlexRequests.Resources -@using PlexRequests.UI.Helpers +@using PlexRequests.UI.Helpers +@using PlexRequests.UI.Resources

@UI.UserLogin_Title

diff --git a/PlexRequests.sln b/PlexRequests.sln index 5bad74ef5..14ef8a36e 100644 --- a/PlexRequests.sln +++ b/PlexRequests.sln @@ -37,8 +37,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Updater", "Ple EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Helpers.Tests", "PlexRequests.Helpers.Tests\PlexRequests.Helpers.Tests.csproj", "{0E6395D3-B074-49E8-898D-0EB99E507E0E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Resources", "PlexRequests.Resources\PlexRequests.Resources.csproj", "{9C266462-BE82-461A-87A2-9EDCFB95D732}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -97,10 +95,6 @@ Global {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Debug|Any CPU.Build.0 = Debug|Any CPU {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0E6395D3-B074-49E8-898D-0EB99E507E0E}.Release|Any CPU.Build.0 = Release|Any CPU - {9C266462-BE82-461A-87A2-9EDCFB95D732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9C266462-BE82-461A-87A2-9EDCFB95D732}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9C266462-BE82-461A-87A2-9EDCFB95D732}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9C266462-BE82-461A-87A2-9EDCFB95D732}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 635fc03c020a7b381ea9fd9bf02a926f43c952d9 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Fri, 24 Jun 2016 11:21:08 +0100 Subject: [PATCH 31/46] Added Dutch language #243 --- PlexRequests.UI/Helpers/CultureHelper.cs | 5 +- PlexRequests.UI/PlexRequests.UI.csproj | 1 + PlexRequests.UI/Resources/UI.Designer.cs | 9 + PlexRequests.UI/Resources/UI.da.resx | 3 + PlexRequests.UI/Resources/UI.de.resx | 3 + PlexRequests.UI/Resources/UI.es.resx | 3 + PlexRequests.UI/Resources/UI.fr.resx | 3 + PlexRequests.UI/Resources/UI.it.resx | 3 + PlexRequests.UI/Resources/UI.nl.resx | 204 ++++++++++++++++++++ PlexRequests.UI/Resources/UI.pt.resx | 3 + PlexRequests.UI/Resources/UI.resx | 3 + PlexRequests.UI/Resources/UI.sv.resx | 3 + PlexRequests.UI/Views/Shared/_Layout.cshtml | 1 + 13 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 PlexRequests.UI/Resources/UI.nl.resx diff --git a/PlexRequests.UI/Helpers/CultureHelper.cs b/PlexRequests.UI/Helpers/CultureHelper.cs index e78758585..d933d758f 100644 --- a/PlexRequests.UI/Helpers/CultureHelper.cs +++ b/PlexRequests.UI/Helpers/CultureHelper.cs @@ -33,7 +33,7 @@ namespace PlexRequests.UI.Helpers { public class CultureHelper { - private static readonly List ValidCultures = new List { "en-US", "de-DE", "fr-FR", "es-ES", "de", "en", "fr", "es","da","sv","it" }; + private static readonly List ValidCultures = new List { "en-US", "de-DE", "fr-FR", "es-ES", "de", "en", "fr", "es","da","sv","it","nl" }; private static readonly List ImplimentedCultures = new List { "en-US", @@ -43,7 +43,8 @@ namespace PlexRequests.UI.Helpers "es", "da", "sv", - "it" + "it", + "nl" }; /// diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index 26f053187..126f0754b 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -582,6 +582,7 @@ + PublicResXFileCodeGenerator diff --git a/PlexRequests.UI/Resources/UI.Designer.cs b/PlexRequests.UI/Resources/UI.Designer.cs index 33937e7c5..4e14e9f44 100644 --- a/PlexRequests.UI/Resources/UI.Designer.cs +++ b/PlexRequests.UI/Resources/UI.Designer.cs @@ -114,6 +114,15 @@ namespace PlexRequests.UI.Resources { } } + /// + /// Looks up a localized string similar to Dutch. + /// + public static string Layout_Dutch { + get { + return ResourceManager.GetString("Layout_Dutch", resourceCulture); + } + } + /// /// Looks up a localized string similar to English. /// diff --git a/PlexRequests.UI/Resources/UI.da.resx b/PlexRequests.UI/Resources/UI.da.resx index e808eb106..93ca45995 100644 --- a/PlexRequests.UI/Resources/UI.da.resx +++ b/PlexRequests.UI/Resources/UI.da.resx @@ -198,4 +198,7 @@ her + + Hollandsk + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.de.resx b/PlexRequests.UI/Resources/UI.de.resx index 765ab5255..6c3cd2089 100644 --- a/PlexRequests.UI/Resources/UI.de.resx +++ b/PlexRequests.UI/Resources/UI.de.resx @@ -198,4 +198,7 @@ hier + + Niederländisch + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.es.resx b/PlexRequests.UI/Resources/UI.es.resx index e7a483f69..7a37c7acc 100644 --- a/PlexRequests.UI/Resources/UI.es.resx +++ b/PlexRequests.UI/Resources/UI.es.resx @@ -198,4 +198,7 @@ aquí + + Holandés + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.fr.resx b/PlexRequests.UI/Resources/UI.fr.resx index 3e22411c5..0f8410740 100644 --- a/PlexRequests.UI/Resources/UI.fr.resx +++ b/PlexRequests.UI/Resources/UI.fr.resx @@ -198,4 +198,7 @@ ici + + Néerlandais + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.it.resx b/PlexRequests.UI/Resources/UI.it.resx index a7f77803c..a1fa4d50a 100644 --- a/PlexRequests.UI/Resources/UI.it.resx +++ b/PlexRequests.UI/Resources/UI.it.resx @@ -198,4 +198,7 @@ Here + + Olandese + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.nl.resx b/PlexRequests.UI/Resources/UI.nl.resx new file mode 100644 index 000000000..4c9d25ea6 --- /dev/null +++ b/PlexRequests.UI/Resources/UI.nl.resx @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Inloggen + + + Wilt u een film of tv-show te kijken, maar het is op het moment niet op Plex? Log hieronder in met uw gebruikersnaam en wachtwoord Plex.tv !! + + + Uw login gegevens worden alleen gebruikt om uw account te verifiëren Plex.! + + + Plex.tv Gebruikersnaam! + + + Gebruikersnaam + + + Wachtwoord + + + Aanmelden! + + + Er is iets fout gegaan + + + Succes + + + Plex Requests + + + Zoeken! + + + Verzoeken + + + UItgaves + + + Doneren. + + + Admin + + + Instellingen + + + Wachtwoord wijzigen + + + Uitloggen + + + Er is een nieuwe update beschikbaar is! Klik! + + + English + + + Spanish + + + German + + + Koffiebroodje + + + Portuguese + + + Zweeds + + + Italian + + + samples/testers + + + Dutch + + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.pt.resx b/PlexRequests.UI/Resources/UI.pt.resx index b1933c073..822d7eea6 100644 --- a/PlexRequests.UI/Resources/UI.pt.resx +++ b/PlexRequests.UI/Resources/UI.pt.resx @@ -198,4 +198,7 @@ aqui + + Holandês + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.resx b/PlexRequests.UI/Resources/UI.resx index 4ed1f4cce..bc954b5ea 100644 --- a/PlexRequests.UI/Resources/UI.resx +++ b/PlexRequests.UI/Resources/UI.resx @@ -179,4 +179,7 @@ Here! + + Dutch + \ No newline at end of file diff --git a/PlexRequests.UI/Resources/UI.sv.resx b/PlexRequests.UI/Resources/UI.sv.resx index 346efcd96..ae512228a 100644 --- a/PlexRequests.UI/Resources/UI.sv.resx +++ b/PlexRequests.UI/Resources/UI.sv.resx @@ -198,4 +198,7 @@ Här.” + + dutch + \ No newline at end of file diff --git a/PlexRequests.UI/Views/Shared/_Layout.cshtml b/PlexRequests.UI/Views/Shared/_Layout.cshtml index 0f1a4ad33..04604dcdf 100644 --- a/PlexRequests.UI/Views/Shared/_Layout.cshtml +++ b/PlexRequests.UI/Views/Shared/_Layout.cshtml @@ -76,6 +76,7 @@
@@ -152,9 +153,9 @@ {{status}}

-
Release Date: {{releaseDate}}
+
@UI.Requests_ReleaseDate: {{releaseDate}}
- Approved: + @UI.Common_Approved: {{#if_eq approved false}} {{/if_eq}} @@ -163,7 +164,7 @@ {{/if_eq}}
- Available + @UI.Requests_Available {{#if_eq available false}} {{/if_eq}} @@ -172,14 +173,14 @@ {{/if_eq}}
{{#if_eq type "tv"}} -
Seasons Requested: {{seriesRequested}}
+
@UI.Requests_SeasonsRequested: {{seriesRequested}}
{{/if_eq}} {{#if requestedUsers}} -
Requested By: {{requestedUsers}}
+
@UI.Requests_RequestedBy: {{requestedUsers}}
{{/if}} -
Requested Date: {{requestedDate}}
+
@UI.Requests_RequestedDate: {{requestedDate}}
- Issue: + @UI.Issues_Issue: {{#if_eq issueId 0}} {{else}} @@ -194,10 +195,10 @@ {{#if_eq hasQualities true}}
- +
{{else}} - + {{/if_eq}} {{/if_eq}}
- +
{{#if_eq available true}} - + {{else}} - + {{/if_eq}}
@@ -230,15 +231,15 @@ @@ -270,9 +271,9 @@ {{status}}

-
Release Date: {{releaseDate}}
+
@UI.Requests_ReleaseDate {{releaseDate}}
- Approved: + @UI.Common_Approved: {{#if_eq approved false}} {{/if_eq}} @@ -281,7 +282,7 @@ {{/if_eq}}
- Available + @UI.Requests_Available {{#if_eq available false}} {{/if_eq}} @@ -290,41 +291,29 @@ {{/if_eq}}
{{#if requestedUsers}} -
Requested By: {{requestedUsers}}
+
@UI.Requests_RequestedBy: {{requestedUsers}}
{{/if}} -
Requested Date: {{requestedDate}}
-
- {{#if otherMessage}} -
Message: {{otherMessage}}
- {{else}} -
Issue: {{issues}}
- {{/if}} -
-
- {{#if adminNote}} -
Note from Admin: {{adminNote}}
- {{/if}} -
+
@UI.Requests_RequestedDate: {{requestedDate}}
{{#if_eq admin true}} {{#if_eq approved false}}
- +
{{/if_eq}}
- +
{{#if_eq available true}} - + {{else}} - + {{/if_eq}}
@@ -334,15 +323,15 @@ @@ -358,7 +347,7 @@ From 419bf0270ea0f3e8e132dbb98dcabdd394aa61cb Mon Sep 17 00:00:00 2001 From: tidusjar Date: Tue, 28 Jun 2016 13:43:01 +0100 Subject: [PATCH 41/46] Fixed some small issues and improved the navbar --- PlexRequests.UI/Views/Requests/Index.cshtml | 4 ++-- PlexRequests.UI/Views/Shared/_Layout.cshtml | 26 ++++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/PlexRequests.UI/Views/Requests/Index.cshtml b/PlexRequests.UI/Views/Requests/Index.cshtml index df0ad42a2..d603ea105 100644 --- a/PlexRequests.UI/Views/Requests/Index.cshtml +++ b/PlexRequests.UI/Views/Requests/Index.cshtml @@ -221,7 +221,7 @@ {{#if_eq available true}} {{else}} - + {{/if_eq}} @@ -231,7 +231,7 @@