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

pull/356/head
tidusjar 8 years ago
parent 7b57e3fffc
commit 63e0d0e531

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

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

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

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

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

@ -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;
}
}
}

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

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

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

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

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

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

@ -45,6 +45,7 @@ namespace PlexRequests.UI.Validators
RuleFor(x => x.BaseUrl).NotEqual("updatechecker").WithMessage("You cannot use 'updatechecker' as this is reserved by the application.");
RuleFor(x => x.BaseUrl).NotEqual("usermanagement").WithMessage("You cannot use 'usermanagement' as this is reserved by the application.");
RuleFor(x => x.BaseUrl).NotEqual("api").WithMessage("You cannot use 'api' as this is reserved by the application.");
RuleFor(x => x.BaseUrl).NotEqual("landing").WithMessage("You cannot use 'landing' as this is reserved by the application.");
}
}
}

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

Loading…
Cancel
Save