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()