Small changes around how we work with custom events in the analytics

This commit is contained in:
tidusjar 2016-06-22 12:59:01 +01:00
parent 7b57e3fffc
commit 63e0d0e531
14 changed files with 1498 additions and 1340 deletions

View file

@ -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<string,string> cookies)
{
return CookieHelper.GetAnalyticClientId(cookies);
}
private static IEnumerable<TestCaseData> GetAnalyticsClientId
{
get
{
yield return new TestCaseData(new Dictionary<string, string>()).Returns(string.Empty);
yield return new TestCaseData(new Dictionary<string, string> { { "_ga", "GA1.1.306549087.1464005217" } }).Returns("306549087.1464005217");
yield return new TestCaseData(new Dictionary<string,string> { {"_ga", "GA1.1.306549087" } }).Returns(string.Empty);
}
}
}
}

View file

@ -1,119 +1,120 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{0E6395D3-B074-49E8-898D-0EB99E507E0E}</ProjectGuid> <ProjectGuid>{0E6395D3-B074-49E8-898D-0EB99E507E0E}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PlexRequests.Helpers.Tests</RootNamespace> <RootNamespace>PlexRequests.Helpers.Tests</RootNamespace>
<AssemblyName>PlexRequests.Helpers.Tests</AssemblyName> <AssemblyName>PlexRequests.Helpers.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion> <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath> <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest> <IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType> <TestProjectType>UnitTest</TestProjectType>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.Owin, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath> <HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Microsoft.Owin.Host.SystemWeb, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.Owin.Host.SystemWeb, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath> <HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.3.0.0\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="nunit.framework, Version=3.0.5813.39031, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> <Reference Include="nunit.framework, Version=3.0.5813.39031, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll</HintPath> <HintPath>..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL"> <Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath> <HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
</ItemGroup> </ItemGroup>
<Choose> <Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'"> <When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup> </ItemGroup>
</When> </When>
<Otherwise> <Otherwise>
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" /> <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup> </ItemGroup>
</Otherwise> </Otherwise>
</Choose> </Choose>
<ItemGroup> <ItemGroup>
<Compile Include="DateTimeHelperTests.cs" /> <Compile Include="CookieHelperTests.cs" />
<Compile Include="PasswordHasherTests.cs" /> <Compile Include="DateTimeHelperTests.cs" />
<Compile Include="HtmlRemoverTests.cs" /> <Compile Include="PasswordHasherTests.cs" />
<Compile Include="AssemblyHelperTests.cs" /> <Compile Include="HtmlRemoverTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="AssemblyHelperTests.cs" />
<Compile Include="PlexHelperTests.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UriHelperTests.cs" /> <Compile Include="PlexHelperTests.cs" />
</ItemGroup> <Compile Include="UriHelperTests.cs" />
<ItemGroup> </ItemGroup>
<None Include="app.config" /> <ItemGroup>
<None Include="packages.config" /> <None Include="app.config" />
</ItemGroup> <None Include="packages.config" />
<ItemGroup> </ItemGroup>
<ProjectReference Include="..\PlexRequests.Helpers\PlexRequests.Helpers.csproj"> <ItemGroup>
<Project>{1252336d-42a3-482a-804c-836e60173dfa}</Project> <ProjectReference Include="..\PlexRequests.Helpers\PlexRequests.Helpers.csproj">
<Name>PlexRequests.Helpers</Name> <Project>{1252336d-42a3-482a-804c-836e60173dfa}</Project>
</ProjectReference> <Name>PlexRequests.Helpers</Name>
</ItemGroup> </ProjectReference>
<Choose> </ItemGroup>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'"> <Choose>
<ItemGroup> <When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <ItemGroup>
<Private>False</Private> <Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
</Reference> <Private>False</Private>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> </Reference>
<Private>False</Private> <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
</Reference> <Private>False</Private>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> </Reference>
<Private>False</Private> <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
</Reference> <Private>False</Private>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> </Reference>
<Private>False</Private> <Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
</Reference> <Private>False</Private>
</ItemGroup> </Reference>
</When> </ItemGroup>
</Choose> </When>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> </Choose>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Other similar extension points exist, see Microsoft.Common.targets. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<Target Name="BeforeBuild"> Other similar extension points exist, see Microsoft.Common.targets.
</Target> <Target Name="BeforeBuild">
<Target Name="AfterBuild"> </Target>
</Target> <Target Name="AfterBuild">
--> </Target>
-->
</Project> </Project>

View file

@ -34,6 +34,7 @@ namespace PlexRequests.Helpers.Analytics
Create, Create,
Save, Save,
Update, Update,
Start Start,
View
} }
} }

View file

@ -47,52 +47,51 @@ namespace PlexRequests.Helpers.Analytics
private static Logger Log = LogManager.GetCurrentClassLogger(); 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 cat = category.ToString();
var act = action.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 cat = category.ToString();
var act = action.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 cat = category.ToString();
var act = action.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 cat = category.ToString();
var act = action.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; 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; 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(category)) throw new ArgumentNullException(nameof(category));
if (string.IsNullOrEmpty(action)) throw new ArgumentNullException(nameof(action)); 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 var postDataString = postData
.Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}"))
@ -101,13 +100,12 @@ namespace PlexRequests.Helpers.Analytics
SendRequest(postDataString); 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(category)) throw new ArgumentNullException(nameof(category));
if (string.IsNullOrEmpty(action)) throw new ArgumentNullException(nameof(action)); 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 var postDataString = postData
.Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}"))
@ -115,12 +113,11 @@ namespace PlexRequests.Helpers.Analytics
await SendRequestAsync(postDataString); 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(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 var postDataString = postData
.Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}"))
@ -129,12 +126,12 @@ namespace PlexRequests.Helpers.Analytics
await SendRequestAsync(postDataString); 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(message)) throw new ArgumentNullException(nameof(message));
if (string.IsNullOrEmpty(username)) throw new ArgumentNullException(nameof(username)); 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 var postDataString = postData
.Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}")) .Aggregate("", (data, next) => string.Format($"{data}&{next.Key}={HttpUtility.UrlEncode(next.Value)}"))
@ -196,20 +193,24 @@ namespace PlexRequests.Helpers.Analytics
} }
} }
private Dictionary<string, string> BuildRequestData(HitType type, string username, string category, string action, string label, int? value, string exceptionDescription, int? fatal) private Dictionary<string, string> BuildRequestData(HitType type, string username, string category, string action, string clientId, string label, int? value, string exceptionDescription, int? fatal)
{ {
var postData = new Dictionary<string, string> var postData = new Dictionary<string, string>
{ {
{ "v", "1" }, { "v", "1" },
{ "tid", TrackingId }, { "tid", TrackingId },
{ "t", type.ToString() }, { "t", type.ToString() }
{"cid", Guid.NewGuid().ToString() }
}; };
if (!string.IsNullOrEmpty(username)) if (!string.IsNullOrEmpty(username))
{ {
postData.Add("uid", username); postData.Add("uid", username);
} }
postData.Add("cid", !string.IsNullOrEmpty(clientId)
? clientId
: Guid.NewGuid().ToString());
if (!string.IsNullOrEmpty(label)) if (!string.IsNullOrEmpty(label))
{ {
postData.Add("el", label); postData.Add("el", label);

View file

@ -37,8 +37,9 @@ namespace PlexRequests.Helpers.Analytics
/// <param name="action">The action.</param> /// <param name="action">The action.</param>
/// <param name="label">The label.</param> /// <param name="label">The label.</param>
/// <param name="username">The username.</param> /// <param name="username">The username.</param>
/// <param name="clientId">The client identifier.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
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);
/// <summary> /// <summary>
/// Tracks the event asynchronous. /// Tracks the event asynchronous.
@ -47,9 +48,10 @@ namespace PlexRequests.Helpers.Analytics
/// <param name="action">The action.</param> /// <param name="action">The action.</param>
/// <param name="label">The label.</param> /// <param name="label">The label.</param>
/// <param name="username">The username.</param> /// <param name="username">The username.</param>
/// <param name="clientId">The client identifier.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns></returns> /// <returns></returns>
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);
/// <summary> /// <summary>
/// Tracks the page view. /// Tracks the page view.
@ -58,8 +60,9 @@ namespace PlexRequests.Helpers.Analytics
/// <param name="action">The action.</param> /// <param name="action">The action.</param>
/// <param name="label">The label.</param> /// <param name="label">The label.</param>
/// <param name="username">The username.</param> /// <param name="username">The username.</param>
/// <param name="clientId">The client identifier.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
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);
/// <summary> /// <summary>
/// Tracks the page view asynchronous. /// Tracks the page view asynchronous.
@ -68,25 +71,28 @@ namespace PlexRequests.Helpers.Analytics
/// <param name="action">The action.</param> /// <param name="action">The action.</param>
/// <param name="label">The label.</param> /// <param name="label">The label.</param>
/// <param name="username">The username.</param> /// <param name="username">The username.</param>
/// <param name="clientId">The client identifier.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns></returns> /// <returns></returns>
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);
/// <summary> /// <summary>
/// Tracks the exception. /// Tracks the exception.
/// </summary> /// </summary>
/// <param name="message">The message.</param> /// <param name="message">The message.</param>
/// <param name="username">The username.</param> /// <param name="username">The username.</param>
/// <param name="clientId">The client identifier.</param>
/// <param name="fatal">if set to <c>true</c> [fatal].</param> /// <param name="fatal">if set to <c>true</c> [fatal].</param>
void TrackException(string message, string username, bool fatal); void TrackException(string message, string username, string clientId, bool fatal);
/// <summary> /// <summary>
/// Tracks the exception asynchronous. /// Tracks the exception asynchronous.
/// </summary> /// </summary>
/// <param name="message">The message.</param> /// <param name="message">The message.</param>
/// <param name="username">The username.</param> /// <param name="username">The username.</param>
/// <param name="clientId">The client identifier.</param>
/// <param name="fatal">if set to <c>true</c> [fatal].</param> /// <param name="fatal">if set to <c>true</c> [fatal].</param>
/// <returns></returns> /// <returns></returns>
Task TrackExceptionAsync(string message, string username, bool fatal); Task TrackExceptionAsync(string message, string username, string clientId, bool fatal);
} }
} }

View file

@ -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";
/// <summary>
/// Gets the analytic client identifier.
/// <para>Example: Value = "GA1.1.306549087.1464005217"</para>
/// </summary>
/// <param name="cookies">The cookies.</param>
/// <returns></returns>
public static string GetAnalyticClientId(IDictionary<string, string> 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;
}
}
}

View file

@ -1,102 +1,103 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1252336D-42A3-482A-804C-836E60173DFA}</ProjectGuid> <ProjectGuid>{1252336D-42A3-482A-804C-836E60173DFA}</ProjectGuid>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PlexRequests.Helpers</RootNamespace> <RootNamespace>PlexRequests.Helpers</RootNamespace>
<AssemblyName>PlexRequests.Helpers</AssemblyName> <AssemblyName>PlexRequests.Helpers</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<TargetFrameworkProfile /> <TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Hangfire.Core, Version=1.5.7.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Hangfire.Core, Version=1.5.7.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Hangfire.Core.1.5.7\lib\net45\Hangfire.Core.dll</HintPath> <HintPath>..\packages\Hangfire.Core.1.5.7\lib\net45\Hangfire.Core.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Nancy, Version=1.4.2.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Nancy, Version=1.4.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath> <HintPath>..\packages\Nancy.1.4.3\lib\net40\Nancy.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.4\lib\net45\NLog.dll</HintPath> <HintPath>..\packages\NLog.4.3.4\lib\net45\NLog.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL"> <Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath> <HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
<Reference Include="System.Runtime.Caching" /> <Reference Include="System.Runtime.Caching" />
<Reference Include="System.Web" /> <Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" /> <Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed"> <Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Analytics\Action.cs" /> <Compile Include="Analytics\Action.cs" />
<Compile Include="Analytics\Analytics.cs" /> <Compile Include="Analytics\Analytics.cs" />
<Compile Include="Analytics\Category.cs" /> <Compile Include="Analytics\Category.cs" />
<Compile Include="Analytics\HitType.cs" /> <Compile Include="Analytics\HitType.cs" />
<Compile Include="Analytics\IAnalytics.cs" /> <Compile Include="Analytics\IAnalytics.cs" />
<Compile Include="AssemblyHelper.cs" /> <Compile Include="AssemblyHelper.cs" />
<Compile Include="ByteConverterHelper.cs" /> <Compile Include="ByteConverterHelper.cs" />
<Compile Include="DateTimeHelper.cs" /> <Compile Include="CookieHelper.cs" />
<Compile Include="Exceptions\ApiRequestException.cs" /> <Compile Include="DateTimeHelper.cs" />
<Compile Include="Exceptions\ApplicationSettingsException.cs" /> <Compile Include="Exceptions\ApiRequestException.cs" />
<Compile Include="HtmlRemover.cs" /> <Compile Include="Exceptions\ApplicationSettingsException.cs" />
<Compile Include="ICacheProvider.cs" /> <Compile Include="HtmlRemover.cs" />
<Compile Include="JsonConvertHelper.cs" /> <Compile Include="ICacheProvider.cs" />
<Compile Include="LoggingHelper.cs" /> <Compile Include="JsonConvertHelper.cs" />
<Compile Include="MemoryCacheProvider.cs" /> <Compile Include="LoggingHelper.cs" />
<Compile Include="ObjectCopier.cs" /> <Compile Include="MemoryCacheProvider.cs" />
<Compile Include="PasswordHasher.cs" /> <Compile Include="ObjectCopier.cs" />
<Compile Include="PlexHelper.cs" /> <Compile Include="PasswordHasher.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="PlexHelper.cs" />
<Compile Include="SerializerSettings.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="StringCipher.cs" /> <Compile Include="SerializerSettings.cs" />
<Compile Include="UriHelper.cs" /> <Compile Include="StringCipher.cs" />
<Compile Include="UserClaims.cs" /> <Compile Include="UriHelper.cs" />
</ItemGroup> <Compile Include="UserClaims.cs" />
<ItemGroup> </ItemGroup>
<None Include="app.config" /> <ItemGroup>
<None Include="packages.config" /> <None Include="app.config" />
</ItemGroup> <None Include="packages.config" />
<ItemGroup /> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <ItemGroup />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Other similar extension points exist, see Microsoft.Common.targets. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<Target Name="BeforeBuild"> Other similar extension points exist, see Microsoft.Common.targets.
</Target> <Target Name="BeforeBuild">
<Target Name="AfterBuild"> </Target>
</Target> <Target Name="AfterBuild">
--> </Target>
-->
</Project> </Project>

View file

@ -1,361 +1,365 @@
#region Copyright #region Copyright
// /************************************************************************ // /************************************************************************
// Copyright (c) 2016 Jamie Rees // Copyright (c) 2016 Jamie Rees
// File: UserLoginModuleTests.cs // File: UserLoginModuleTests.cs
// Created By: Jamie Rees // Created By: Jamie Rees
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
// the following conditions: // the following conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Moq; using Moq;
using Nancy; using Nancy;
using Nancy.Testing; using Nancy.Testing;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NUnit.Framework; using NUnit.Framework;
using PlexRequests.Api.Interfaces; using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models.Plex; using PlexRequests.Api.Models.Plex;
using PlexRequests.Core; using PlexRequests.Core;
using PlexRequests.Core.SettingModels; using PlexRequests.Core.SettingModels;
using PlexRequests.Services.Interfaces; using PlexRequests.Services.Interfaces;
using PlexRequests.Store.Models; using PlexRequests.Store.Models;
using PlexRequests.Store.Repository; using PlexRequests.Store.Repository;
using PlexRequests.UI.Models; using PlexRequests.UI.Models;
using PlexRequests.UI.Modules; using PlexRequests.UI.Modules;
using PlexRequests.Helpers; using PlexRequests.Helpers;
using PlexRequests.UI.Helpers; using PlexRequests.Helpers.Analytics;
using PlexRequests.UI.Helpers;
namespace PlexRequests.UI.Tests
{ namespace PlexRequests.UI.Tests
[TestFixture] {
public class AdminModuleTests [TestFixture]
{ public class AdminModuleTests
private Mock<ISettingsService<PlexRequestSettings>> PlexRequestMock { get; set; } {
private Mock<ISettingsService<CouchPotatoSettings>> CpMock { get; set; } private Mock<ISettingsService<PlexRequestSettings>> PlexRequestMock { get; set; }
private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; } private Mock<ISettingsService<CouchPotatoSettings>> CpMock { get; set; }
private Mock<ISettingsService<PlexSettings>> PlexSettingsMock { get; set; } private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; }
private Mock<ISettingsService<SonarrSettings>> SonarrSettingsMock { get; set; } private Mock<ISettingsService<PlexSettings>> PlexSettingsMock { get; set; }
private Mock<ISettingsService<SickRageSettings>> SickRageSettingsMock { get; set; } private Mock<ISettingsService<SonarrSettings>> SonarrSettingsMock { get; set; }
private Mock<ISettingsService<ScheduledJobsSettings>> ScheduledJobsSettingsMock { get; set; } private Mock<ISettingsService<SickRageSettings>> SickRageSettingsMock { get; set; }
private Mock<ISettingsService<EmailNotificationSettings>> EmailMock { get; set; } private Mock<ISettingsService<ScheduledJobsSettings>> ScheduledJobsSettingsMock { get; set; }
private Mock<ISettingsService<PushbulletNotificationSettings>> PushbulletSettings { get; set; } private Mock<ISettingsService<EmailNotificationSettings>> EmailMock { get; set; }
private Mock<ISettingsService<PushoverNotificationSettings>> PushoverSettings { get; set; } private Mock<ISettingsService<PushbulletNotificationSettings>> PushbulletSettings { get; set; }
private Mock<ISettingsService<HeadphonesSettings>> HeadphonesSettings { get; set; } private Mock<ISettingsService<PushoverNotificationSettings>> PushoverSettings { get; set; }
private Mock<IPlexApi> PlexMock { get; set; } private Mock<ISettingsService<HeadphonesSettings>> HeadphonesSettings { get; set; }
private Mock<ISonarrApi> SonarrApiMock { get; set; } private Mock<IPlexApi> PlexMock { get; set; }
private Mock<IPushbulletApi> PushbulletApi { get; set; } private Mock<ISonarrApi> SonarrApiMock { get; set; }
private Mock<IPushoverApi> PushoverApi { get; set; } private Mock<IPushbulletApi> PushbulletApi { get; set; }
private Mock<ICouchPotatoApi> CpApi { get; set; } private Mock<IPushoverApi> PushoverApi { get; set; }
private Mock<IJobRecord> RecorderMock { get; set; } private Mock<ICouchPotatoApi> CpApi { get; set; }
private Mock<IRepository<LogEntity>> LogRepo { get; set; } private Mock<IJobRecord> RecorderMock { get; set; }
private Mock<INotificationService> NotificationService { get; set; } private Mock<IRepository<LogEntity>> LogRepo { get; set; }
private Mock<ICacheProvider> Cache { get; set; } private Mock<INotificationService> NotificationService { get; set; }
private Mock<ISettingsService<LogSettings>> Log { get; set; } private Mock<ICacheProvider> Cache { get; set; }
private Mock<ISettingsService<SlackNotificationSettings>> SlackSettings { get; set; } private Mock<ISettingsService<LogSettings>> Log { get; set; }
private Mock<ISettingsService<LandingPageSettings>> LandingPageSettings { get; set; } private Mock<ISettingsService<SlackNotificationSettings>> SlackSettings { get; set; }
private Mock<ISlackApi> SlackApi { get; set; } private Mock<ISettingsService<LandingPageSettings>> LandingPageSettings { get; set; }
private Mock<ISlackApi> SlackApi { get; set; }
private ConfigurableBootstrapper Bootstrapper { get; set; } private Mock<IAnalytics> IAnalytics { get; set; }
[SetUp] private ConfigurableBootstrapper Bootstrapper { get; set; }
public void Setup()
{ [SetUp]
AuthMock = new Mock<ISettingsService<AuthenticationSettings>>(); public void Setup()
var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; {
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); AuthMock = new Mock<ISettingsService<AuthenticationSettings>>();
var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" };
PlexMock = new Mock<IPlexApi>(); AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
PlexMock.Setup(x => x.SignIn("Username1", "Password1"))
.Returns(new PlexAuthentication { user = new User { authentication_token = "abc", title = "Username1" } }); PlexMock = new Mock<IPlexApi>();
PlexMock.Setup(x => x.SignIn("Username1", "Password1"))
PlexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>(); .Returns(new PlexAuthentication { user = new User { authentication_token = "abc", title = "Username1" } });
PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings());
CpMock = new Mock<ISettingsService<CouchPotatoSettings>>(); PlexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>();
PlexSettingsMock = new Mock<ISettingsService<PlexSettings>>(); PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings());
SonarrApiMock = new Mock<ISonarrApi>(); CpMock = new Mock<ISettingsService<CouchPotatoSettings>>();
SonarrSettingsMock = new Mock<ISettingsService<SonarrSettings>>(); PlexSettingsMock = new Mock<ISettingsService<PlexSettings>>();
EmailMock = new Mock<ISettingsService<EmailNotificationSettings>>(); SonarrApiMock = new Mock<ISonarrApi>();
PushbulletApi = new Mock<IPushbulletApi>(); SonarrSettingsMock = new Mock<ISettingsService<SonarrSettings>>();
PushbulletSettings = new Mock<ISettingsService<PushbulletNotificationSettings>>(); EmailMock = new Mock<ISettingsService<EmailNotificationSettings>>();
CpApi = new Mock<ICouchPotatoApi>(); PushbulletApi = new Mock<IPushbulletApi>();
SickRageSettingsMock = new Mock<ISettingsService<SickRageSettings>>(); PushbulletSettings = new Mock<ISettingsService<PushbulletNotificationSettings>>();
LogRepo = new Mock<IRepository<LogEntity>>(); CpApi = new Mock<ICouchPotatoApi>();
PushoverSettings = new Mock<ISettingsService<PushoverNotificationSettings>>(); SickRageSettingsMock = new Mock<ISettingsService<SickRageSettings>>();
PushoverApi = new Mock<IPushoverApi>(); LogRepo = new Mock<IRepository<LogEntity>>();
NotificationService = new Mock<INotificationService>(); PushoverSettings = new Mock<ISettingsService<PushoverNotificationSettings>>();
HeadphonesSettings = new Mock<ISettingsService<HeadphonesSettings>>(); PushoverApi = new Mock<IPushoverApi>();
Cache = new Mock<ICacheProvider>(); NotificationService = new Mock<INotificationService>();
Log = new Mock<ISettingsService<LogSettings>>(); HeadphonesSettings = new Mock<ISettingsService<HeadphonesSettings>>();
SlackApi = new Mock<ISlackApi>(); Cache = new Mock<ICacheProvider>();
SlackSettings = new Mock<ISettingsService<SlackNotificationSettings>>(); Log = new Mock<ISettingsService<LogSettings>>();
LandingPageSettings = new Mock<ISettingsService<LandingPageSettings>>(); SlackApi = new Mock<ISlackApi>();
ScheduledJobsSettingsMock = new Mock<ISettingsService<ScheduledJobsSettings>>(); SlackSettings = new Mock<ISettingsService<SlackNotificationSettings>>();
RecorderMock = new Mock<IJobRecord>(); LandingPageSettings = new Mock<ISettingsService<LandingPageSettings>>();
ScheduledJobsSettingsMock = new Mock<ISettingsService<ScheduledJobsSettings>>();
RecorderMock = new Mock<IJobRecord>();
Bootstrapper = new ConfigurableBootstrapper(with => IAnalytics = new Mock<IAnalytics>();
{
with.Module<AdminModule>();
with.Dependency(AuthMock.Object); Bootstrapper = new ConfigurableBootstrapper(with =>
with.Dependency(PlexRequestMock.Object); {
with.Dependency(CpMock.Object); with.Module<AdminModule>();
with.Dependency(PlexSettingsMock.Object); with.Dependency(AuthMock.Object);
with.Dependency(SonarrApiMock.Object); with.Dependency(PlexRequestMock.Object);
with.Dependency(SonarrSettingsMock.Object); with.Dependency(CpMock.Object);
with.Dependency(PlexMock.Object); with.Dependency(PlexSettingsMock.Object);
with.Dependency(EmailMock.Object); with.Dependency(SonarrApiMock.Object);
with.Dependency(PushbulletApi.Object); with.Dependency(SonarrSettingsMock.Object);
with.Dependency(PushbulletSettings.Object); with.Dependency(PlexMock.Object);
with.Dependency(CpApi.Object); with.Dependency(EmailMock.Object);
with.Dependency(SickRageSettingsMock.Object); with.Dependency(PushbulletApi.Object);
with.Dependency(LogRepo.Object); with.Dependency(PushbulletSettings.Object);
with.Dependency(PushoverSettings.Object); with.Dependency(CpApi.Object);
with.Dependency(PushoverApi.Object); with.Dependency(SickRageSettingsMock.Object);
with.Dependency(NotificationService.Object); with.Dependency(LogRepo.Object);
with.Dependency(HeadphonesSettings.Object); with.Dependency(PushoverSettings.Object);
with.Dependency(Cache.Object); with.Dependency(PushoverApi.Object);
with.Dependency(Log.Object); with.Dependency(NotificationService.Object);
with.Dependency(SlackApi.Object); with.Dependency(IAnalytics.Object);
with.Dependency(LandingPageSettings.Object); with.Dependency(HeadphonesSettings.Object);
with.Dependency(SlackSettings.Object); with.Dependency(Cache.Object);
with.Dependency(ScheduledJobsSettingsMock.Object); with.Dependency(Log.Object);
with.Dependency(RecorderMock.Object); with.Dependency(SlackApi.Object);
with.RootPathProvider<TestRootPathProvider>(); with.Dependency(LandingPageSettings.Object);
with.RequestStartup((container, pipelines, context) => with.Dependency(SlackSettings.Object);
{ with.Dependency(ScheduledJobsSettingsMock.Object);
context.CurrentUser = new UserIdentity { UserName = "user", Claims = new List<string> {"Admin"} }; with.Dependency(RecorderMock.Object);
}); with.RootPathProvider<TestRootPathProvider>();
}); with.RequestStartup((container, pipelines, context) =>
{
Bootstrapper.WithSession(new Dictionary<string, object>()); context.CurrentUser = new UserIdentity { UserName = "user", Claims = new List<string> {"Admin"} };
} });
});
[Test]
public void RequestAuthTokenTestNewSettings() Bootstrapper.WithSession(new Dictionary<string, object>());
{ }
var browser = new Browser(Bootstrapper);
[Test]
var result = browser.Post("/admin/requestauth", with => public void RequestAuthTokenTestNewSettings()
{ {
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", "Username1"); var result = browser.Post("/admin/requestauth", with =>
with.FormValue("password", "Password1"); {
with.HttpRequest();
}); with.Header("Accept", "application/json");
with.FormValue("username", "Username1");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("password", "Password1");
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString()); });
Assert.That(body.Result, Is.EqualTo(true));
PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
AuthMock.Verify(x => x.GetSettings(), Times.Once);
AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Once); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
} Assert.That(body.Result, Is.EqualTo(true));
PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once);
[Test] AuthMock.Verify(x => x.GetSettings(), Times.Once);
public void RequestAuthTokenTestEmptyCredentials() AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Once);
{ }
var browser = new Browser(Bootstrapper);
[Test]
var result = browser.Post("/admin/requestauth", with => public void RequestAuthTokenTestEmptyCredentials()
{ {
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", string.Empty); var result = browser.Post("/admin/requestauth", with =>
with.FormValue("password", "Password1"); {
with.HttpRequest();
}); with.Header("Accept", "application/json");
with.FormValue("username", string.Empty);
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("password", "Password1");
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString()); });
Assert.That(body.Result, Is.EqualTo(false));
Assert.That(body.Message, Is.Not.Empty); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Never); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
AuthMock.Verify(x => x.GetSettings(), Times.Never); Assert.That(body.Result, Is.EqualTo(false));
AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Never); Assert.That(body.Message, Is.Not.Empty);
}
PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Never);
[Test] AuthMock.Verify(x => x.GetSettings(), Times.Never);
public void RequestAuthTokenTesPlexSignInFail() AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Never);
{ }
var browser = new Browser(Bootstrapper);
[Test]
var result = browser.Post("/admin/requestauth", with => public void RequestAuthTokenTesPlexSignInFail()
{ {
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", "Badusername"); var result = browser.Post("/admin/requestauth", with =>
with.FormValue("password", "Password1"); {
with.HttpRequest();
}); with.Header("Accept", "application/json");
with.FormValue("username", "Badusername");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("password", "Password1");
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString()); });
Assert.That(body.Result, Is.EqualTo(false));
Assert.That(body.Message, Is.Not.Empty); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
PlexMock.Verify(x => x.SignIn("Badusername", "Password1"), Times.Once); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
AuthMock.Verify(x => x.GetSettings(), Times.Never); Assert.That(body.Result, Is.EqualTo(false));
AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Never); Assert.That(body.Message, Is.Not.Empty);
}
PlexMock.Verify(x => x.SignIn("Badusername", "Password1"), Times.Once);
[Test] AuthMock.Verify(x => x.GetSettings(), Times.Never);
public void RequestAuthTokenTestExistingSettings() AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Never);
{ }
AuthMock.Setup(x => x.GetSettings()).Returns(() => null);
var browser = new Browser(Bootstrapper); [Test]
public void RequestAuthTokenTestExistingSettings()
var result = browser.Post("/admin/requestauth", with => {
{ AuthMock.Setup(x => x.GetSettings()).Returns(() => null);
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", "Username1"); var result = browser.Post("/admin/requestauth", with =>
with.FormValue("password", "Password1"); {
with.HttpRequest();
}); with.Header("Accept", "application/json");
with.FormValue("username", "Username1");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("password", "Password1");
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString()); });
Assert.That(body.Result, Is.EqualTo(true));
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once);
AuthMock.Verify(x => x.GetSettings(), Times.Once); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Once); Assert.That(body.Result, Is.EqualTo(true));
}
PlexMock.Verify(x => x.SignIn("Username1", "Password1"), Times.Once);
[Test] AuthMock.Verify(x => x.GetSettings(), Times.Once);
public void GetUsersSuccessfully() AuthMock.Verify(x => x.SaveSettings(It.IsAny<AuthenticationSettings>()), Times.Once);
{ }
var users = new PlexFriends { User = new[] { new UserFriends { Title = "abc2" }, } };
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(users); [Test]
var browser = new Browser(Bootstrapper); public void GetUsersSuccessfully()
{
var result = browser.Get("/admin/getusers", with => var users = new PlexFriends { User = new[] { new UserFriends { Title = "abc2" }, } };
{ PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(users);
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", "Username1"); var result = browser.Get("/admin/getusers", with =>
with.FormValue("password", "Password1"); {
with.HttpRequest();
}); with.Header("Accept", "application/json");
with.FormValue("username", "Username1");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("password", "Password1");
});
var body = JsonConvert.DeserializeObject<JObject>(result.Body.AsString());
var user = body["users"]; Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
Assert.That(body, Is.Not.Null);
Assert.That(user.ToString().Contains("abc"), Is.True);
var body = JsonConvert.DeserializeObject<JObject>(result.Body.AsString());
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once); var user = body["users"];
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(body, Is.Not.Null);
} Assert.That(user.ToString().Contains("abc"), Is.True);
[Test] PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
public void GetUsersReturnsNoUsers() AuthMock.Verify(x => x.GetSettings(), Times.Once);
{ }
var users = new PlexFriends();
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(users); [Test]
var browser = new Browser(Bootstrapper); public void GetUsersReturnsNoUsers()
{
var result = browser.Get("/admin/getusers", with => var users = new PlexFriends();
{ PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(users);
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", "Username1"); var result = browser.Get("/admin/getusers", with =>
with.FormValue("password", "Password1"); {
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<string>(result.Body.AsString()); });
Assert.That(body, Is.Not.Null);
Assert.That(string.IsNullOrWhiteSpace(body), Is.True); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once); var body = JsonConvert.DeserializeObject<string>(result.Body.AsString());
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(body, Is.Not.Null);
} Assert.That(string.IsNullOrWhiteSpace(body), Is.True);
[Test] PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
public void GetUsersReturnsNull() AuthMock.Verify(x => x.GetSettings(), Times.Once);
{ }
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(() => null);
var browser = new Browser(Bootstrapper); [Test]
public void GetUsersReturnsNull()
var result = browser.Get("/admin/getusers", with => {
{ PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(() => null);
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", "Username1"); var result = browser.Get("/admin/getusers", with =>
with.FormValue("password", "Password1"); {
with.HttpRequest();
}); with.Header("Accept", "application/json");
with.FormValue("username", "Username1");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("password", "Password1");
var body = JsonConvert.DeserializeObject<string>(result.Body.AsString()); });
Assert.That(body, Is.Not.Null);
Assert.That(string.IsNullOrWhiteSpace(body), Is.True); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once); var body = JsonConvert.DeserializeObject<string>(result.Body.AsString());
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(body, Is.Not.Null);
} Assert.That(string.IsNullOrWhiteSpace(body), Is.True);
[Test] PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
public void GetUsersTokenIsNull() AuthMock.Verify(x => x.GetSettings(), Times.Once);
{ }
AuthMock.Setup(x => x.GetSettings()).Returns(new AuthenticationSettings());
var browser = new Browser(Bootstrapper); [Test]
public void GetUsersTokenIsNull()
var result = browser.Get("/admin/getusers", with => {
{ AuthMock.Setup(x => x.GetSettings()).Returns(new AuthenticationSettings());
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("username", "Username1"); var result = browser.Get("/admin/getusers", with =>
with.FormValue("password", "Password1"); {
with.HttpRequest();
}); with.Header("Accept", "application/json");
with.FormValue("username", "Username1");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("password", "Password1");
var body = JsonConvert.DeserializeObject<JObject>(result.Body.AsString()); });
var user = (string)body["users"];
Assert.That(body, Is.Not.Null); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
Assert.That(string.IsNullOrWhiteSpace(user), Is.True);
var body = JsonConvert.DeserializeObject<JObject>(result.Body.AsString());
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never); var user = (string)body["users"];
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(body, Is.Not.Null);
} Assert.That(string.IsNullOrWhiteSpace(user), Is.True);
}
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
AuthMock.Verify(x => x.GetSettings(), Times.Once);
}
}
} }

View file

@ -1,437 +1,441 @@
#region Copyright #region Copyright
// /************************************************************************ // /************************************************************************
// Copyright (c) 2016 Jamie Rees // Copyright (c) 2016 Jamie Rees
// File: UserLoginModuleTests.cs // File: UserLoginModuleTests.cs
// Created By: Jamie Rees // Created By: Jamie Rees
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
// the following conditions: // the following conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Moq; using Moq;
using Nancy; using Nancy;
using Nancy.Testing; using Nancy.Testing;
using Newtonsoft.Json; using Newtonsoft.Json;
using NUnit.Framework; using NUnit.Framework;
using PlexRequests.Api.Interfaces; using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models.Plex; using PlexRequests.Api.Models.Plex;
using PlexRequests.Core; using PlexRequests.Core;
using PlexRequests.Core.SettingModels; using PlexRequests.Core.SettingModels;
using PlexRequests.UI.Models; using PlexRequests.Helpers.Analytics;
using PlexRequests.UI.Modules; using PlexRequests.UI.Models;
using PlexRequests.UI.Modules;
namespace PlexRequests.UI.Tests
{ namespace PlexRequests.UI.Tests
[TestFixture] {
public class UserLoginModuleTests [TestFixture]
{ public class UserLoginModuleTests
private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; } {
private Mock<ISettingsService<PlexRequestSettings>> PlexRequestMock { get; set; } private Mock<ISettingsService<AuthenticationSettings>> AuthMock { get; set; }
private Mock<ISettingsService<LandingPageSettings>> LandingPageMock { get; set; } private Mock<ISettingsService<PlexRequestSettings>> PlexRequestMock { get; set; }
private ConfigurableBootstrapper Bootstrapper { get; set; } private Mock<ISettingsService<LandingPageSettings>> LandingPageMock { get; set; }
private Mock<IPlexApi> PlexMock { get; set; } private ConfigurableBootstrapper Bootstrapper { get; set; }
private Mock<IPlexApi> PlexMock { get; set; }
[SetUp] private Mock<IAnalytics> IAnalytics { get; set; }
public void Setup()
{ [SetUp]
AuthMock = new Mock<ISettingsService<AuthenticationSettings>>(); public void Setup()
PlexMock = new Mock<IPlexApi>(); {
LandingPageMock = new Mock<ISettingsService<LandingPageSettings>>(); AuthMock = new Mock<ISettingsService<AuthenticationSettings>>();
PlexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>(); PlexMock = new Mock<IPlexApi>();
PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); LandingPageMock = new Mock<ISettingsService<LandingPageSettings>>();
PlexRequestMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(new PlexRequestSettings())); PlexRequestMock = new Mock<ISettingsService<PlexRequestSettings>>();
LandingPageMock.Setup(x => x.GetSettings()).Returns(new LandingPageSettings()); PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings());
Bootstrapper = new ConfigurableBootstrapper(with => PlexRequestMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(new PlexRequestSettings()));
{ LandingPageMock.Setup(x => x.GetSettings()).Returns(new LandingPageSettings());
with.Module<UserLoginModule>(); IAnalytics = new Mock<IAnalytics>();
with.Dependency(PlexRequestMock.Object); Bootstrapper = new ConfigurableBootstrapper(with =>
with.Dependency(AuthMock.Object); {
with.Dependency(PlexMock.Object); with.Module<UserLoginModule>();
with.Dependency(LandingPageMock.Object); with.Dependency(PlexRequestMock.Object);
with.RootPathProvider<TestRootPathProvider>(); with.Dependency(AuthMock.Object);
}); with.Dependency(PlexMock.Object);
} with.Dependency(LandingPageMock.Object);
with.Dependency(IAnalytics.Object);
[Test] with.RootPathProvider<TestRootPathProvider>();
public void LoginWithoutAuthentication() });
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" };
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); [Test]
public void LoginWithoutAuthentication()
Bootstrapper.WithSession(new Dictionary<string, object>()); {
var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" };
var browser = new Browser(Bootstrapper); AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", "abc"); var result = browser.Post("/userlogin", with =>
}); {
with.HttpRequest();
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.Header("Accept", "application/json");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); with.FormValue("Username", "abc");
});
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(true)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc"));
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
} Assert.That(body.Result, Is.EqualTo(true));
AuthMock.Verify(x => x.GetSettings(), Times.Once);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
public void LoginWithoutAuthenticationWithEmptyUsername() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" };
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); [Test]
public void LoginWithoutAuthenticationWithEmptyUsername()
{
Bootstrapper.WithSession(new Dictionary<string, object>()); var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" };
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
var browser = new Browser(Bootstrapper);
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", string.Empty); var result = browser.Post("/userlogin", with =>
}); {
with.HttpRequest();
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.Header("Accept", "application/json");
with.FormValue("Username", string.Empty);
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString()); });
Assert.That(body.Result, Is.EqualTo(false));
AuthMock.Verify(x => x.GetSettings(), Times.Never); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
} Assert.That(body.Result, Is.EqualTo(false));
AuthMock.Verify(x => x.GetSettings(), Times.Never);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
public void LoginWithUsernameSuccessfully() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" };
var plexFriends = new PlexFriends [Test]
{ public void LoginWithUsernameSuccessfully()
User = new[] {
{ var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" };
new UserFriends var plexFriends = new PlexFriends
{ {
Title = "abc", User = new[]
}, {
} new UserFriends
}; {
Title = "abc",
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); },
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends); }
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount()); };
Bootstrapper.WithSession(new Dictionary<string, object>()); AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
var browser = new Browser(Bootstrapper); PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount());
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", "abc"); var result = browser.Post("/userlogin", with =>
}); {
with.HttpRequest();
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.Header("Accept", "application/json");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); with.FormValue("Username", "abc");
});
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(true)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc"));
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
} Assert.That(body.Result, Is.EqualTo(true));
AuthMock.Verify(x => x.GetSettings(), Times.Once);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
public void LoginWithUsernameUnSuccessfully() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" };
var plexFriends = new PlexFriends [Test]
{ public void LoginWithUsernameUnSuccessfully()
User = new[] {
{ var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" };
new UserFriends var plexFriends = new PlexFriends
{ {
Username = "aaaa", User = new[]
}, {
} new UserFriends
}; {
Username = "aaaa",
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); },
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends); }
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount()); };
Bootstrapper.WithSession(new Dictionary<string, object>()); AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
var browser = new Browser(Bootstrapper); PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount());
var result = browser.Post("/userlogin", with => Bootstrapper.WithSession(new Dictionary<string, object>());
{
with.HttpRequest(); var browser = new Browser(Bootstrapper);
with.Header("Accept", "application/json");
with.FormValue("Username", "abc"); var result = browser.Post("/userlogin", with =>
}); {
with.HttpRequest();
with.Header("Accept", "application/json");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("Username", "abc");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); });
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(false)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
Assert.That(body.Message, Is.Not.Empty); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null);
AuthMock.Verify(x => x.GetSettings(), Times.Once);
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once); Assert.That(body.Result, Is.EqualTo(false));
} Assert.That(body.Message, Is.Not.Empty);
AuthMock.Verify(x => x.GetSettings(), Times.Once);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
public void LoginWithUsernameAndPasswordSuccessfully() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" };
var plexFriends = new PlexFriends [Test]
{ public void LoginWithUsernameAndPasswordSuccessfully()
User = new[] {
{ var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" };
new UserFriends var plexFriends = new PlexFriends
{ {
Title = "abc", User = new[]
} {
} new UserFriends
}; {
var plexAuth = new PlexAuthentication Title = "abc",
{ }
user = new User }
{ };
authentication_token = "abc" var plexAuth = new PlexAuthentication
} {
}; user = new User
{
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); authentication_token = "abc"
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends); }
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth); };
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount());
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
Bootstrapper.WithSession(new Dictionary<string, object>()); PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth);
var browser = new Browser(Bootstrapper); PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(new PlexAccount());
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", "abc"); var result = browser.Post("/userlogin", with =>
with.FormValue("Password", "abc"); {
}); with.HttpRequest();
with.Header("Accept", "application/json");
with.FormValue("Username", "abc");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("Password", "abc");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc")); });
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(true)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("abc"));
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
} Assert.That(body.Result, Is.EqualTo(true));
AuthMock.Verify(x => x.GetSettings(), Times.Once);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
public void LoginWithUsernameAndPasswordUnSuccessfully() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" };
var plexFriends = new PlexFriends [Test]
{ public void LoginWithUsernameAndPasswordUnSuccessfully()
User = new[] {
{ var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" };
new UserFriends var plexFriends = new PlexFriends
{ {
Username = "abc", User = new[]
}, {
} new UserFriends
}; {
var plexAuth = new PlexAuthentication Username = "abc",
{ },
user = null }
}; };
var plexAuth = new PlexAuthentication
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); {
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends); user = null
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth); };
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
Bootstrapper.WithSession(new Dictionary<string, object>()); PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth);
var browser = new Browser(Bootstrapper);
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", "abc"); var result = browser.Post("/userlogin", with =>
with.FormValue("Password", "abc"); {
}); with.HttpRequest();
with.Header("Accept", "application/json");
with.FormValue("Username", "abc");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("Password", "abc");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); });
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(false)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
Assert.That(body.Message, Is.Not.Empty); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null);
AuthMock.Verify(x => x.GetSettings(), Times.Once);
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Once); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never); Assert.That(body.Result, Is.EqualTo(false));
} Assert.That(body.Message, Is.Not.Empty);
AuthMock.Verify(x => x.GetSettings(), Times.Once);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
public void AttemptToLoginAsDeniedUser() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = false, DeniedUsers = "abc", PlexAuthToken = "abc" };
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); [Test]
public void AttemptToLoginAsDeniedUser()
Bootstrapper.WithSession(new Dictionary<string, object>()); {
var expectedSettings = new AuthenticationSettings { UserAuthentication = false, DeniedUsers = "abc", PlexAuthToken = "abc" };
var browser = new Browser(Bootstrapper); AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", "abc"); var result = browser.Post("/userlogin", with =>
}); {
with.HttpRequest();
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.Header("Accept", "application/json");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); with.FormValue("Username", "abc");
});
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(false)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
Assert.That(body.Message, Is.Not.Empty); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null);
AuthMock.Verify(x => x.GetSettings(), Times.Once);
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never); Assert.That(body.Result, Is.EqualTo(false));
} Assert.That(body.Message, Is.Not.Empty);
AuthMock.Verify(x => x.GetSettings(), Times.Once);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
public void Logout() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
{ }
Bootstrapper.WithSession(new Dictionary<string, object> { { SessionKeys.UsernameKey, "abc" } });
[Test]
var browser = new Browser(Bootstrapper); public void Logout()
var result = browser.Get("/userlogin/logout", with => {
{ Bootstrapper.WithSession(new Dictionary<string, object> { { SessionKeys.UsernameKey, "abc" } });
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
}); var result = browser.Get("/userlogin/logout", with =>
{
Assert.That(HttpStatusCode.SeeOther, Is.EqualTo(result.StatusCode)); with.HttpRequest();
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null); with.Header("Accept", "application/json");
} });
[Test] Assert.That(HttpStatusCode.SeeOther, Is.EqualTo(result.StatusCode));
public void LoginWithOwnerUsernameSuccessfully() Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.Null);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" };
var plexFriends = new PlexFriends [Test]
{ public void LoginWithOwnerUsernameSuccessfully()
User = new[] {
{ var expectedSettings = new AuthenticationSettings { UserAuthentication = true, PlexAuthToken = "abc" };
new UserFriends() var plexFriends = new PlexFriends
} {
}; User = new[]
{
var account = new PlexAccount { Username = "Jamie" }; new UserFriends()
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); }
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends); };
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(account);
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(new PlexAuthentication { user = new User { username = "Jamie" } }); var account = new PlexAccount { Username = "Jamie" };
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
Bootstrapper.WithSession(new Dictionary<string, object>()); PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(account);
var browser = new Browser(Bootstrapper); PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(new PlexAuthentication { user = new User { username = "Jamie" } });
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", "Jamie"); var result = browser.Post("/userlogin", with =>
}); {
with.HttpRequest();
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.Header("Accept", "application/json");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("Jamie")); with.FormValue("Username", "Jamie");
});
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(true)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("Jamie"));
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
} Assert.That(body.Result, Is.EqualTo(true));
AuthMock.Verify(x => x.GetSettings(), Times.Once);
[Test] PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
public void LoginWithOwnerUsernameAndPasswordSuccessfully() PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Once);
{ }
var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" };
var plexFriends = new PlexFriends [Test]
{ public void LoginWithOwnerUsernameAndPasswordSuccessfully()
User = new[] {
{ var expectedSettings = new AuthenticationSettings { UserAuthentication = true, UsePassword = true, PlexAuthToken = "abc" };
new UserFriends() var plexFriends = new PlexFriends
} {
}; User = new[]
var plexAuth = new PlexAuthentication {
{ new UserFriends()
user = new User }
{ };
authentication_token = "abc", var plexAuth = new PlexAuthentication
username = "Jamie" {
} user = new User
}; {
authentication_token = "abc",
var account = new PlexAccount { Username = "Jamie" }; username = "Jamie"
}
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); };
PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth); var account = new PlexAccount { Username = "Jamie" };
PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(account);
AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings);
Bootstrapper.WithSession(new Dictionary<string, object>()); PlexMock.Setup(x => x.GetUsers(It.IsAny<string>())).Returns(plexFriends);
PlexMock.Setup(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>())).Returns(plexAuth);
var browser = new Browser(Bootstrapper); PlexMock.Setup(x => x.GetAccount(It.IsAny<string>())).Returns(account);
var result = browser.Post("/userlogin", with =>
{ Bootstrapper.WithSession(new Dictionary<string, object>());
with.HttpRequest();
with.Header("Accept", "application/json"); var browser = new Browser(Bootstrapper);
with.FormValue("Username", "jamie"); var result = browser.Post("/userlogin", with =>
with.FormValue("Password", "abc"); {
}); with.HttpRequest();
with.Header("Accept", "application/json");
with.FormValue("Username", "jamie");
Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode)); with.FormValue("Password", "abc");
Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("jamie")); });
var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
Assert.That(body.Result, Is.EqualTo(true)); Assert.That(HttpStatusCode.OK, Is.EqualTo(result.StatusCode));
AuthMock.Verify(x => x.GetSettings(), Times.Once); Assert.That(result.Context.Request.Session[SessionKeys.UsernameKey], Is.EqualTo("jamie"));
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never); var body = JsonConvert.DeserializeObject<JsonResponseModel>(result.Body.AsString());
} Assert.That(body.Result, Is.EqualTo(true));
} AuthMock.Verify(x => x.GetSettings(), Times.Once);
PlexMock.Verify(x => x.SignIn(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
PlexMock.Verify(x => x.GetUsers(It.IsAny<string>()), Times.Never);
}
}
} }

View file

@ -32,7 +32,6 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic; using System.Collections.Generic;
using System.Dynamic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -52,6 +51,7 @@ using PlexRequests.Api.Interfaces;
using PlexRequests.Core; using PlexRequests.Core;
using PlexRequests.Core.SettingModels; using PlexRequests.Core.SettingModels;
using PlexRequests.Helpers; using PlexRequests.Helpers;
using PlexRequests.Helpers.Analytics;
using PlexRequests.Helpers.Exceptions; using PlexRequests.Helpers.Exceptions;
using PlexRequests.Services.Interfaces; using PlexRequests.Services.Interfaces;
using PlexRequests.Services.Notification; using PlexRequests.Services.Notification;
@ -60,6 +60,7 @@ using PlexRequests.Store.Repository;
using PlexRequests.UI.Helpers; using PlexRequests.UI.Helpers;
using PlexRequests.UI.Models; using PlexRequests.UI.Models;
using Action = PlexRequests.Helpers.Analytics.Action;
namespace PlexRequests.UI.Modules namespace PlexRequests.UI.Modules
{ {
@ -89,6 +90,7 @@ namespace PlexRequests.UI.Modules
private ISettingsService<ScheduledJobsSettings> ScheduledJobSettings { get; } private ISettingsService<ScheduledJobsSettings> ScheduledJobSettings { get; }
private ISlackApi SlackApi { get; } private ISlackApi SlackApi { get; }
private IJobRecord JobRecorder { get; } private IJobRecord JobRecorder { get; }
private IAnalytics Analytics { get; }
private static Logger Log = LogManager.GetCurrentClassLogger(); private static Logger Log = LogManager.GetCurrentClassLogger();
public AdminModule(ISettingsService<PlexRequestSettings> prService, public AdminModule(ISettingsService<PlexRequestSettings> prService,
@ -111,7 +113,7 @@ namespace PlexRequests.UI.Modules
ISettingsService<LogSettings> logs, ISettingsService<LogSettings> logs,
ICacheProvider cache, ISettingsService<SlackNotificationSettings> slackSettings, ICacheProvider cache, ISettingsService<SlackNotificationSettings> slackSettings,
ISlackApi slackApi, ISettingsService<LandingPageSettings> lp, ISlackApi slackApi, ISettingsService<LandingPageSettings> lp,
ISettingsService<ScheduledJobsSettings> scheduler, IJobRecord rec) : base("admin", prService) ISettingsService<ScheduledJobsSettings> scheduler, IJobRecord rec, IAnalytics analytics) : base("admin", prService)
{ {
PrService = prService; PrService = prService;
CpService = cpService; CpService = cpService;
@ -137,6 +139,7 @@ namespace PlexRequests.UI.Modules
LandingSettings = lp; LandingSettings = lp;
ScheduledJobSettings = scheduler; ScheduledJobSettings = scheduler;
JobRecorder = rec; JobRecorder = rec;
Analytics = analytics;
this.RequiresClaims(UserClaims.Admin); this.RequiresClaims(UserClaims.Admin);
@ -237,7 +240,7 @@ namespace PlexRequests.UI.Modules
return View["Settings", settings]; return View["Settings", settings];
} }
private Response SaveAdmin() private async Task<Response> SaveAdmin()
{ {
var model = this.Bind<PlexRequestSettings>(); var model = this.Bind<PlexRequestSettings>();
var valid = this.Validate(model); var valid = this.Validate(model);
@ -254,6 +257,8 @@ namespace PlexRequests.UI.Modules
} }
} }
var result = PrService.SaveSettings(model); var result = PrService.SaveSettings(model);
await Analytics.TrackEventAsync(Category.Admin, Action.Save, "PlexRequestSettings", Username, CookieHelper.GetAnalyticClientId(Cookies));
return Response.AsJson(result return Response.AsJson(result
? new JsonResponseModel { Result = true } ? new JsonResponseModel { Result = true }
: new JsonResponseModel { Result = false, Message = "We could not save to the database, please try again" }); : new JsonResponseModel { Result = false, Message = "We could not save to the database, please try again" });

View file

@ -1,68 +1,69 @@
#region Copyright #region Copyright
// /************************************************************************ // /************************************************************************
// Copyright (c) 2016 Jamie Rees // Copyright (c) 2016 Jamie Rees
// File: BaseModule.cs // File: BaseModule.cs
// Created By: Jamie Rees // Created By: Jamie Rees
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
// the following conditions: // the following conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System; using System;
using System.Linq; using System.Collections.Generic;
using System.Linq;
using Nancy;
using Nancy;
using PlexRequests.Core;
using PlexRequests.Core.SettingModels; using PlexRequests.Core;
using PlexRequests.Helpers; using PlexRequests.Core.SettingModels;
using PlexRequests.UI.Models; using PlexRequests.Helpers;
using PlexRequests.UI.Models;
namespace PlexRequests.UI.Modules
{ namespace PlexRequests.UI.Modules
public abstract class BaseModule : NancyModule {
{ public abstract class BaseModule : NancyModule
protected string BaseUrl { get; set; } {
protected string BaseUrl { get; set; }
protected BaseModule(ISettingsService<PlexRequestSettings> settingsService)
{ protected BaseModule(ISettingsService<PlexRequestSettings> settingsService)
var settings = settingsService.GetSettings(); {
var baseUrl = settings.BaseUrl; var settings = settingsService.GetSettings();
BaseUrl = baseUrl; var baseUrl = settings.BaseUrl;
BaseUrl = baseUrl;
var modulePath = string.IsNullOrEmpty(baseUrl) ? string.Empty : baseUrl;
var modulePath = string.IsNullOrEmpty(baseUrl) ? string.Empty : baseUrl;
ModulePath = modulePath;
} ModulePath = modulePath;
}
protected BaseModule(string modulePath, ISettingsService<PlexRequestSettings> settingsService)
{ protected BaseModule(string modulePath, ISettingsService<PlexRequestSettings> settingsService)
var settings = settingsService.GetSettings(); {
var baseUrl = settings.BaseUrl; var settings = settingsService.GetSettings();
BaseUrl = baseUrl; var baseUrl = settings.BaseUrl;
BaseUrl = baseUrl;
var settingModulePath = string.IsNullOrEmpty(baseUrl) ? modulePath : $"{baseUrl}/{modulePath}";
var settingModulePath = string.IsNullOrEmpty(baseUrl) ? modulePath : $"{baseUrl}/{modulePath}";
ModulePath = settingModulePath;
} ModulePath = settingModulePath;
}
private int _dateTimeOffset = -1;
private int _dateTimeOffset = -1;
protected int DateTimeOffset protected int DateTimeOffset
{ {
get get
@ -73,7 +74,7 @@ namespace PlexRequests.UI.Modules
} }
return _dateTimeOffset; return _dateTimeOffset;
} }
} }
private string _username; private string _username;
protected string Username protected string Username
@ -82,12 +83,21 @@ namespace PlexRequests.UI.Modules
{ {
if (string.IsNullOrEmpty(_username)) if (string.IsNullOrEmpty(_username))
{ {
_username = Session[SessionKeys.UsernameKey].ToString(); try
{
_username = Session[SessionKeys.UsernameKey].ToString();
}
catch (Exception)
{
return string.Empty;
}
} }
return _username; return _username;
} }
} }
protected IDictionary<string, string> Cookies => Request.Cookies;
protected bool IsAdmin protected bool IsAdmin
{ {
get get
@ -100,6 +110,6 @@ namespace PlexRequests.UI.Modules
return claims.Contains(UserClaims.Admin) || claims.Contains(UserClaims.PowerUser); return claims.Contains(UserClaims.Admin) || claims.Contains(UserClaims.PowerUser);
} }
} }
} }
} }

View file

@ -1,220 +1,235 @@
#region Copyright #region Copyright
// /************************************************************************ // /************************************************************************
// Copyright (c) 2016 Jamie Rees // Copyright (c) 2016 Jamie Rees
// File: UserLoginModule.cs // File: UserLoginModule.cs
// Created By: Jamie Rees // Created By: Jamie Rees
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
// the following conditions: // the following conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// ************************************************************************/ // ************************************************************************/
#endregion #endregion
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Nancy; using Nancy;
using Nancy.Extensions; using Nancy.Extensions;
using Nancy.Responses.Negotiation; using Nancy.Responses.Negotiation;
using NLog; using NLog;
using PlexRequests.Api.Interfaces; using PlexRequests.Api.Interfaces;
using PlexRequests.Api.Models.Plex; using PlexRequests.Api.Models.Plex;
using PlexRequests.Core; using PlexRequests.Core;
using PlexRequests.Core.SettingModels; using PlexRequests.Core.SettingModels;
using PlexRequests.UI.Models; using PlexRequests.Helpers;
using PlexRequests.Helpers.Analytics;
namespace PlexRequests.UI.Modules using PlexRequests.UI.Models;
{
public class UserLoginModule : BaseModule using Action = PlexRequests.Helpers.Analytics.Action;
{
public UserLoginModule(ISettingsService<AuthenticationSettings> auth, IPlexApi api, ISettingsService<PlexRequestSettings> pr, ISettingsService<LandingPageSettings> lp) : base("userlogin", pr) namespace PlexRequests.UI.Modules
{ {
AuthService = auth; public class UserLoginModule : BaseModule
LandingPageSettings = lp; {
Api = api; public UserLoginModule(ISettingsService<AuthenticationSettings> auth, IPlexApi api, ISettingsService<PlexRequestSettings> pr, ISettingsService<LandingPageSettings> lp, IAnalytics a) : base("userlogin", pr)
Get["/", true] = async (x, ct) => await Index(); {
Post["/"] = x => LoginUser(); AuthService = auth;
Get["/logout"] = x => Logout(); LandingPageSettings = lp;
} Analytics = a;
Api = api;
private ISettingsService<AuthenticationSettings> AuthService { get; } Get["/", true] = async (x, ct) => await Index();
private ISettingsService<LandingPageSettings> LandingPageSettings { get; } Post["/"] = x => LoginUser();
private IPlexApi Api { get; } Get["/logout"] = x => Logout();
}
private static Logger Log = LogManager.GetCurrentClassLogger();
private ISettingsService<AuthenticationSettings> AuthService { get; }
public async Task<Negotiator> Index() private ISettingsService<LandingPageSettings> LandingPageSettings { get; }
{ private IPlexApi Api { get; }
var query = Request.Query["landing"]; private IAnalytics Analytics { get; }
var landingCheck = (bool?)query ?? true;
if (landingCheck) private static Logger Log = LogManager.GetCurrentClassLogger();
{
var landingSettings = await LandingPageSettings.GetSettingsAsync(); public async Task<Negotiator> Index()
{
if (landingSettings.Enabled) var query = Request.Query["landing"];
{ var landingCheck = (bool?)query ?? true;
if (landingSettings.BeforeLogin) if (landingCheck)
{ {
var model = new LandingPageViewModel var landingSettings = await LandingPageSettings.GetSettingsAsync();
{
Enabled = landingSettings.Enabled, if (landingSettings.Enabled)
Id = landingSettings.Id, {
EnabledNoticeTime = landingSettings.EnabledNoticeTime,
NoticeEnable = landingSettings.NoticeEnable, if (landingSettings.BeforeLogin)
NoticeEnd = landingSettings.NoticeEnd, {
NoticeMessage = landingSettings.NoticeMessage, await
NoticeStart = landingSettings.NoticeStart, Analytics.TrackEventAsync(
ContinueUrl = landingSettings.BeforeLogin ? $"userlogin" : $"search" Category.LandingPage,
}; Action.View,
"Going To LandingPage before login",
return View["Landing/Index", model]; Username,
} CookieHelper.GetAnalyticClientId(Cookies));
}
} var model = new LandingPageViewModel
var settings = await AuthService.GetSettingsAsync(); {
return View["Index", settings]; Enabled = landingSettings.Enabled,
} Id = landingSettings.Id,
EnabledNoticeTime = landingSettings.EnabledNoticeTime,
private Response LoginUser() NoticeEnable = landingSettings.NoticeEnable,
{ NoticeEnd = landingSettings.NoticeEnd,
var dateTimeOffset = Request.Form.DateTimeOffset; NoticeMessage = landingSettings.NoticeMessage,
var username = Request.Form.username.Value; NoticeStart = landingSettings.NoticeStart,
Log.Debug("Username \"{0}\" attempting to login", username); ContinueUrl = landingSettings.BeforeLogin ? $"userlogin" : $"search"
if (string.IsNullOrWhiteSpace(username)) };
{
return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" }); return View["Landing/Index", model];
} }
}
var authenticated = false; }
var settings = await AuthService.GetSettingsAsync();
var settings = AuthService.GetSettings(); return View["Index", settings];
}
if (IsUserInDeniedList(username, settings))
{ private Response LoginUser()
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 dateTimeOffset = Request.Form.DateTimeOffset;
} var username = Request.Form.username.Value;
Log.Debug("Username \"{0}\" attempting to login", username);
var password = string.Empty; if (string.IsNullOrWhiteSpace(username))
if (settings.UsePassword) {
{ return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" });
Log.Debug("Using password"); }
password = Request.Form.password.Value;
} var authenticated = false;
var settings = AuthService.GetSettings();
if (settings.UserAuthentication && settings.UsePassword) // Authenticate with Plex
{ if (IsUserInDeniedList(username, settings))
Log.Debug("Need to auth and also provide pass"); {
var signedIn = (PlexAuthentication)Api.SignIn(username, password); Log.Debug("User is in denied list, not allowing them to authenticate");
if (signedIn.user?.authentication_token != null) return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" });
{ }
Log.Debug("Correct credentials, checking if the user is account owner or in the friends list");
if (CheckIfUserIsOwner(settings.PlexAuthToken, signedIn.user?.username)) var password = string.Empty;
{ if (settings.UsePassword)
Log.Debug("User is the account owner"); {
authenticated = true; Log.Debug("Using password");
} password = Request.Form.password.Value;
else }
{
authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken);
Log.Debug("Friends list result = {0}", authenticated); if (settings.UserAuthentication && settings.UsePassword) // Authenticate with Plex
} {
} Log.Debug("Need to auth and also provide pass");
} var signedIn = (PlexAuthentication)Api.SignIn(username, password);
else if (settings.UserAuthentication) // Check against the users in Plex if (signedIn.user?.authentication_token != null)
{ {
Log.Debug("Need to auth"); Log.Debug("Correct credentials, checking if the user is account owner or in the friends list");
authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken); if (CheckIfUserIsOwner(settings.PlexAuthToken, signedIn.user?.username))
if (CheckIfUserIsOwner(settings.PlexAuthToken, username)) {
{ Log.Debug("User is the account owner");
Log.Debug("User is the account owner"); authenticated = true;
authenticated = true; }
} else
Log.Debug("Friends list result = {0}", authenticated); {
} authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken);
else if (!settings.UserAuthentication) // No auth, let them pass! Log.Debug("Friends list result = {0}", authenticated);
{ }
Log.Debug("No need to auth"); }
authenticated = true; }
} else if (settings.UserAuthentication) // Check against the users in Plex
{
if (authenticated) Log.Debug("Need to auth");
{ authenticated = CheckIfUserIsInPlexFriends(username, settings.PlexAuthToken);
Log.Debug("We are authenticated! Setting session."); if (CheckIfUserIsOwner(settings.PlexAuthToken, username))
// Add to the session (Used in the BaseModules) {
Session[SessionKeys.UsernameKey] = (string)username; Log.Debug("User is the account owner");
} authenticated = true;
}
Session[SessionKeys.ClientDateTimeOffsetKey] = (int)dateTimeOffset; Log.Debug("Friends list result = {0}", authenticated);
}
if (!authenticated) else if (!settings.UserAuthentication) // No auth, let them pass!
{ {
return Response.AsJson(new JsonResponseModel {Result = false, Message = "Incorrect User or Password"}); Log.Debug("No need to auth");
} authenticated = true;
}
var landingSettings = LandingPageSettings.GetSettings();
if (authenticated)
if (landingSettings.Enabled) {
{ Log.Debug("We are authenticated! Setting session.");
if (!landingSettings.BeforeLogin) // Add to the session (Used in the BaseModules)
return Response.AsJson(new JsonResponseModel { Result = true, Message = "landing" }); Session[SessionKeys.UsernameKey] = (string)username;
} }
return Response.AsJson(new JsonResponseModel {Result = true, Message = "search" });
} Session[SessionKeys.ClientDateTimeOffsetKey] = (int)dateTimeOffset;
if (!authenticated)
{
private Response Logout() return Response.AsJson(new JsonResponseModel { Result = false, Message = "Incorrect User or Password" });
{ }
Log.Debug("Logging Out");
if (Session[SessionKeys.UsernameKey] != null) var landingSettings = LandingPageSettings.GetSettings();
{
Session.Delete(SessionKeys.UsernameKey); if (landingSettings.Enabled)
} {
return Context.GetRedirect(!string.IsNullOrEmpty(BaseUrl) if (!landingSettings.BeforeLogin)
? $"~/{BaseUrl}/userlogin" return Response.AsJson(new JsonResponseModel { Result = true, Message = "landing" });
: "~/userlogin"); }
} return Response.AsJson(new JsonResponseModel { Result = true, Message = "search" });
}
private bool CheckIfUserIsOwner(string authToken, string userName)
{
var userAccount = Api.GetAccount(authToken);
if (userAccount == null) private Response Logout()
{ {
return false; Log.Debug("Logging Out");
} if (Session[SessionKeys.UsernameKey] != null)
return userAccount.Username != null && userAccount.Username.Equals(userName, StringComparison.CurrentCultureIgnoreCase); {
} Session.Delete(SessionKeys.UsernameKey);
}
private bool CheckIfUserIsInPlexFriends(string username, string authToken) return Context.GetRedirect(!string.IsNullOrEmpty(BaseUrl)
{ ? $"~/{BaseUrl}/userlogin"
var users = Api.GetUsers(authToken); : "~/userlogin");
var allUsers = users?.User?.Where(x => !string.IsNullOrEmpty(x.Title)); }
return allUsers != null && allUsers.Any(x => x.Title.Equals(username, StringComparison.CurrentCultureIgnoreCase));
} private bool CheckIfUserIsOwner(string authToken, string userName)
{
private bool IsUserInDeniedList(string username, AuthenticationSettings settings) var userAccount = Api.GetAccount(authToken);
{ if (userAccount == null)
return settings.DeniedUserList.Any(x => x.Equals(username)); {
} 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));
}
}
} }

View file

@ -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("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("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("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.");
} }
} }
} }

View file

@ -17,7 +17,7 @@
<title>Plex Requests</title> <title>Plex Requests</title>
<!-- Styles --> <!-- Styles -->
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
@Html.LoadAnalytics()
@Html.LoadAssets() @Html.LoadAssets()
</head> </head>
<body> <body>