diff --git a/PlexRequests.Api.Interfaces/IApiRequest.cs b/PlexRequests.Api.Interfaces/IApiRequest.cs index 602fc14f8..5b3e0d556 100644 --- a/PlexRequests.Api.Interfaces/IApiRequest.cs +++ b/PlexRequests.Api.Interfaces/IApiRequest.cs @@ -33,5 +33,6 @@ namespace PlexRequests.Api.Interfaces public interface IApiRequest { T Execute(IRestRequest request, Uri baseUri) where T : new(); + T ExecuteXml(IRestRequest request, Uri baseUri) where T : class; } } diff --git a/PlexRequests.Api/ApiRequest.cs b/PlexRequests.Api/ApiRequest.cs index add96c3da..f5f573066 100644 --- a/PlexRequests.Api/ApiRequest.cs +++ b/PlexRequests.Api/ApiRequest.cs @@ -25,8 +25,13 @@ // ************************************************************************/ #endregion using System; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Serialization; using PlexRequests.Api.Interfaces; +using PlexRequests.Api.Models; using RestSharp; @@ -57,5 +62,29 @@ namespace PlexRequests.Api return response.Data; } + + public T ExecuteXml(IRestRequest request, Uri baseUri) where T : class + { + var client = new RestClient { BaseUrl = baseUri }; + + var response = client.Execute(request); + + if (response.ErrorException != null) + { + var message = "Error retrieving response. Check inner details for more info."; + throw new ApplicationException(message, response.ErrorException); + } + + return Deserialize(response.Content); + } + + public T Deserialize(string input) + where T : class + { + var ser = new XmlSerializer(typeof(T)); + + using (var sr = new StringReader(input)) + return (T)ser.Deserialize(sr); + } } } diff --git a/PlexRequests.Api/Models/PlexFriends.cs b/PlexRequests.Api/Models/PlexFriends.cs index a35c712d6..db3523057 100644 --- a/PlexRequests.Api/Models/PlexFriends.cs +++ b/PlexRequests.Api/Models/PlexFriends.cs @@ -71,7 +71,7 @@ namespace PlexRequests.Api.Models public class PlexFriends { [XmlElement(ElementName = "User")] - public List User { get; set; } + public UserFriends[] User { get; set; } [XmlAttribute(AttributeName = "friendlyName")] public string FriendlyName { get; set; } [XmlAttribute(AttributeName = "identifier")] diff --git a/PlexRequests.Api/PlexApi.cs b/PlexRequests.Api/PlexApi.cs index 95e71700f..833e5fd57 100644 --- a/PlexRequests.Api/PlexApi.cs +++ b/PlexRequests.Api/PlexApi.cs @@ -27,6 +27,7 @@ using System; using PlexRequests.Api.Models; +using PlexRequests.Helpers; using RestSharp; @@ -34,6 +35,12 @@ namespace PlexRequests.Api { public class PlexApi { + static PlexApi() + { + Version = AssemblyHelper.GetAssemblyVersion(); + } + private static string Version { get; set; } + public PlexAuthentication GetToken(string username, string password) { var userModel = new PlexUserRequest @@ -51,7 +58,7 @@ namespace PlexRequests.Api request.AddHeader("X-Plex-Client-Identifier", "Test213"); // TODO need something unique to the users version/installation request.AddHeader("X-Plex-Product", "Request Plex"); - request.AddHeader("X-Plex-Version", "0.0.1"); + request.AddHeader("X-Plex-Version", Version); request.AddHeader("Content-Type", "application/json"); request.AddJsonBody(userModel); @@ -69,12 +76,12 @@ namespace PlexRequests.Api request.AddHeader("X-Plex-Client-Identifier", "Test213"); request.AddHeader("X-Plex-Product", "Request Plex"); - request.AddHeader("X-Plex-Version", "0.0.1"); + request.AddHeader("X-Plex-Version", Version); request.AddHeader("X-Plex-Token", authToken); request.AddHeader("Content-Type", "application/xml"); var api = new ApiRequest(); - var users = api.Execute(request, new Uri("https://plex.tv/pms/friends/all")); + var users = api.ExecuteXml(request, new Uri("https://plex.tv/pms/friends/all")); return users; } diff --git a/PlexRequests.Core.Tests/AuthenticationSettingsTests.cs b/PlexRequests.Core.Tests/AuthenticationSettingsTests.cs new file mode 100644 index 000000000..784117cfa --- /dev/null +++ b/PlexRequests.Core.Tests/AuthenticationSettingsTests.cs @@ -0,0 +1,59 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: AuthenticationSettingsTests.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 NUnit.Framework; + +using PlexRequests.Core.SettingModels; + +namespace PlexRequests.Core.Tests +{ + [TestFixture] + public class AuthenticationSettingsTests + { + [Test, TestCaseSource(nameof(UserData))] + public void DeniedUserListTest(string users, string[] expected) + { + var model = new AuthenticationSettings { DeniedUsers = users }; + + var result = model.DeniedUserList; + + Assert.That(result.Count, Is.EqualTo(expected.Length)); + for (var i = 0; i < expected.Length; i++) + { + Assert.That(result[i], Is.EqualTo(expected[i])); + } + } + + static readonly object[] UserData = + { + new object[] { "john", new [] {"john"} }, + new object[] { "john , abc ,", new [] {"john", "abc"} }, + new object[] { "john,, cde", new [] {"john", "cde"} }, + new object[] { "john,,, aaa , baaa , ", new [] {"john","aaa","baaa"} }, + new object[] { "john, aaa , baaa , maaa, caaa", new [] {"john","aaa","baaa", "maaa", "caaa"} }, + }; + } +} \ No newline at end of file diff --git a/PlexRequests.Core.Tests/PlexRequests.Core.Tests.csproj b/PlexRequests.Core.Tests/PlexRequests.Core.Tests.csproj new file mode 100644 index 000000000..0d255c9af --- /dev/null +++ b/PlexRequests.Core.Tests/PlexRequests.Core.Tests.csproj @@ -0,0 +1,100 @@ + + + + Debug + AnyCPU + {FCFECD5D-47F6-454D-8692-E27A921BE655} + Library + Properties + PlexRequests.Core.Tests + PlexRequests.Core.Tests + v4.5.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + ..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll + True + + + ..\packages\AutoFixture.3.40.0\lib\net40\Ploeh.AutoFixture.dll + True + + + + + + + + + + + + + + + + + + + + + {DD7DC444-D3BF-4027-8AB9-EFC71F5EC581} + PlexRequests.Core + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.Core.Tests/Properties/AssemblyInfo.cs b/PlexRequests.Core.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..874fc2052 --- /dev/null +++ b/PlexRequests.Core.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PlexRequests.Core.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PlexRequests.Core.Tests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fcfecd5d-47f6-454d-8692-e27a921be655")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PlexRequests.Core.Tests/packages.config b/PlexRequests.Core.Tests/packages.config new file mode 100644 index 000000000..780aeade8 --- /dev/null +++ b/PlexRequests.Core.Tests/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PlexRequests.Core/PlexRequests.Core.csproj b/PlexRequests.Core/PlexRequests.Core.csproj index 42655d5b8..945305f9f 100644 --- a/PlexRequests.Core/PlexRequests.Core.csproj +++ b/PlexRequests.Core/PlexRequests.Core.csproj @@ -65,10 +65,11 @@ + - + diff --git a/PlexRequests.Core/SettingModels/RequestPlexSettings.cs b/PlexRequests.Core/SettingModels/PlexRequestSettings.cs similarity index 88% rename from PlexRequests.Core/SettingModels/RequestPlexSettings.cs rename to PlexRequests.Core/SettingModels/PlexRequestSettings.cs index 61edffa5d..668e1321c 100644 --- a/PlexRequests.Core/SettingModels/RequestPlexSettings.cs +++ b/PlexRequests.Core/SettingModels/PlexRequestSettings.cs @@ -1,7 +1,7 @@ #region Copyright // /************************************************************************ // Copyright (c) 2016 Jamie Rees -// File: RequestPlexSettings.cs +// File: PlexRequestSettings.cs // Created By: Jamie Rees // // Permission is hereby granted, free of charge, to any person obtaining @@ -26,11 +26,10 @@ #endregion namespace PlexRequests.Core.SettingModels { - public class RequestPlexSettings : Settings + public class PlexRequestSettings : Settings { public int Port { get; set; } - public bool UserAuthentication { get; set; } - public string PlexAuthToken { get; set; } + public bool SearchForMovies { get; set; } public bool SearchForTvShows { get; set; } public bool RequireApprovial { get; set; } diff --git a/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj b/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj new file mode 100644 index 000000000..7e5c09cd0 --- /dev/null +++ b/PlexRequests.UI.Tests/PlexRequests.UI.Tests.csproj @@ -0,0 +1,93 @@ + + + + Debug + AnyCPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4} + Library + Properties + PlexRequests.UI.Tests + PlexRequests.UI.Tests + v4.5.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll + True + + + ..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll + True + + + ..\packages\AutoFixture.3.40.0\lib\net40\Ploeh.AutoFixture.dll + True + + + + + + + + + + + + + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.UI.Tests/Properties/AssemblyInfo.cs b/PlexRequests.UI.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a6da2256b --- /dev/null +++ b/PlexRequests.UI.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PlexRequests.UI.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PlexRequests.UI.Tests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a930e2cf-79e2-45f9-b06a-9a719a254ce4")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PlexRequests.UI.Tests/packages.config b/PlexRequests.UI.Tests/packages.config new file mode 100644 index 000000000..780aeade8 --- /dev/null +++ b/PlexRequests.UI.Tests/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PlexRequests.UI/Bootstrapper.cs b/PlexRequests.UI/Bootstrapper.cs index db4c3bda8..a1f3672cc 100644 --- a/PlexRequests.UI/Bootstrapper.cs +++ b/PlexRequests.UI/Bootstrapper.cs @@ -56,8 +56,9 @@ namespace PlexRequests.UI container.Register(); container.Register(); - container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); container.Register, SettingsServiceV2>(); + container.Register, SettingsServiceV2>(); container.Register, GenericRepository>(); base.ConfigureRequestContainer(container, context); diff --git a/PlexRequests.UI/Modules/AdminModule.cs b/PlexRequests.UI/Modules/AdminModule.cs index 2917e1431..007fec367 100644 --- a/PlexRequests.UI/Modules/AdminModule.cs +++ b/PlexRequests.UI/Modules/AdminModule.cs @@ -42,17 +42,22 @@ namespace PlexRequests.UI.Modules { public class AdminModule : NancyModule { - private ISettingsService RpService { get; set; } + private ISettingsService RpService { get; set; } private ISettingsService CpService { get; set; } - public AdminModule(ISettingsService rpService, ISettingsService cpService ) : base("admin") + private ISettingsService AuthService { get; set; } + public AdminModule(ISettingsService rpService, ISettingsService cpService, ISettingsService auth) : base("admin") { RpService = rpService; CpService = cpService; + AuthService = auth; #if !DEBUG this.RequiresAuthentication(); #endif Get["/"] = _ => Admin(); + Get["/authentication"] = _ => Authentication(); + Post["/authentication"] = _ => SaveAuthentication(); + Post["/"] = _ => SaveAdmin(); Post["/requestauth"] = _ => RequestAuthToken(); @@ -63,6 +68,24 @@ namespace PlexRequests.UI.Modules Post["/couchpotato"] = _ => SaveCouchPotato(); } + private Negotiator Authentication() + { + var settings = AuthService.GetSettings(); + + return View["/Authentication", settings]; + } + + private Response SaveAuthentication() + { + var model = this.Bind(); + + var result = AuthService.SaveSettings(model); + if (result) + { + return Context.GetRedirect("~/admin/authentication"); + } + return Context.GetRedirect("~/error"); //TODO create error page + } private Negotiator Admin() { @@ -70,12 +93,12 @@ namespace PlexRequests.UI.Modules var settings = RpService.GetSettings(); model = settings; - return View["/Admin/Settings", model]; + return View["/Settings", model]; } private Response SaveAdmin() { - var model = this.Bind(); + var model = this.Bind(); RpService.SaveSettings(model); @@ -89,24 +112,24 @@ namespace PlexRequests.UI.Modules if (string.IsNullOrEmpty(user.username) || string.IsNullOrEmpty(user.password)) { - return Context.GetRedirect("~/admin?error=true"); + return Response.AsJson(new { Result = false, Message = "Please provide a valid username and password" }); } var plex = new PlexApi(); var model = plex.GetToken(user.username, user.password); - var oldSettings = RpService.GetSettings(); + var oldSettings = AuthService.GetSettings(); if (oldSettings != null) { oldSettings.PlexAuthToken = model.user.authentication_token; - RpService.SaveSettings(oldSettings); + AuthService.SaveSettings(oldSettings); } else { - var newModel = new RequestPlexSettings + var newModel = new AuthenticationSettings { PlexAuthToken = model.user.authentication_token }; - RpService.SaveSettings(newModel); + AuthService.SaveSettings(newModel); } return Response.AsJson(new {Result = true, AuthToken = model.user.authentication_token}); @@ -115,7 +138,7 @@ namespace PlexRequests.UI.Modules private Response GetUsers() { - var token = RpService.GetSettings().PlexAuthToken; + var token = AuthService.GetSettings().PlexAuthToken; var api = new PlexApi(); var users = api.GetUsers(token); var usernames = users.User.Select(x => x.Username); @@ -130,6 +153,7 @@ namespace PlexRequests.UI.Modules return View["/Admin/CouchPotato", model]; } + private Response SaveCouchPotato() { var couchPotatoSettings = this.Bind(); diff --git a/PlexRequests.UI/Modules/RequestsModule.cs b/PlexRequests.UI/Modules/RequestsModule.cs index bfe61b86d..5e83f7b00 100644 --- a/PlexRequests.UI/Modules/RequestsModule.cs +++ b/PlexRequests.UI/Modules/RequestsModule.cs @@ -78,7 +78,7 @@ namespace PlexRequests.UI.Modules RequestedBy = tv.RequestedBy, ReleaseYear = tv.ReleaseDate.Year.ToString() }).ToList(); - //TODO check if Available + //TODO check if Available in CP return Response.AsJson(viewModel); } @@ -101,7 +101,7 @@ namespace PlexRequests.UI.Modules RequestedBy = tv.RequestedBy, ReleaseYear = tv.ReleaseDate.Year.ToString() }).ToList(); - //TODO check if Available + //TODO check if Available in Sonarr return Response.AsJson(viewModel); } diff --git a/PlexRequests.UI/PlexRequests.UI.csproj b/PlexRequests.UI/PlexRequests.UI.csproj index a9fabc669..beb7ec9ca 100644 --- a/PlexRequests.UI/PlexRequests.UI.csproj +++ b/PlexRequests.UI/PlexRequests.UI.csproj @@ -244,6 +244,9 @@ Always + + Always + web.config diff --git a/PlexRequests.UI/Program.cs b/PlexRequests.UI/Program.cs index f747ec028..6ebc947a3 100644 --- a/PlexRequests.UI/Program.cs +++ b/PlexRequests.UI/Program.cs @@ -25,7 +25,6 @@ // ************************************************************************/ #endregion using System; -using System.Collections.Generic; using System.Data; using Microsoft.Owin.Hosting; @@ -34,8 +33,6 @@ using Mono.Data.Sqlite; using NLog; using NLog.Config; -using NLog.LayoutRenderers; -using NLog.Layouts; using NLog.Targets; using PlexRequests.Core; @@ -77,7 +74,7 @@ namespace PlexRequests.UI private static string GetStartupUri() { var uri = "http://localhost:3579/"; - var service = new SettingsServiceV2(new JsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); + var service = new SettingsServiceV2(new JsonRepository(new DbConfiguration(new SqliteFactory()), new MemoryCacheProvider())); var settings = service.GetSettings(); if (settings.Port != 0) @@ -95,9 +92,13 @@ namespace PlexRequests.UI var config = new LoggingConfiguration(); // Step 2. Create targets and add them to the configuration - var databaseTarget = new DatabaseTarget { CommandType = CommandType.Text,ConnectionString = connectionString, + var databaseTarget = new DatabaseTarget + { + CommandType = CommandType.Text, + ConnectionString = connectionString, DBProvider = "Mono.Data.Sqlite, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756", - Name = "database"}; + Name = "database" + }; var messageParam = new DatabaseParameterInfo { Name = "@Message", Layout = "${message}" }; @@ -131,7 +132,7 @@ namespace PlexRequests.UI } catch (Exception e) { - + throw; } diff --git a/PlexRequests.UI/Views/Admin/Authentication.cshtml b/PlexRequests.UI/Views/Admin/Authentication.cshtml new file mode 100644 index 000000000..6a97851ee --- /dev/null +++ b/PlexRequests.UI/Views/Admin/Authentication.cshtml @@ -0,0 +1,157 @@ +@Html.Partial("/Admin/_Sidebar") + +
+
+
+ Authentication Settings + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+
+ +
+
+ + +
+
+ Current users that are allowed to authenticate: +
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/Settings.cshtml b/PlexRequests.UI/Views/Admin/Settings.cshtml index 9ee447639..2f09f59cc 100644 --- a/PlexRequests.UI/Views/Admin/Settings.cshtml +++ b/PlexRequests.UI/Views/Admin/Settings.cshtml @@ -65,63 +65,6 @@ -
- -
- -
-
- -
- -
- -
-
- -
-
-
-
- -
-
- -
- -
- -
-
-
-
- Current users that are allowed to authenticate: -
-
-
- -
-
-
-
-
- -
-
- -
-
-
-
@@ -131,68 +74,4 @@
- - - - \ No newline at end of file + \ No newline at end of file diff --git a/PlexRequests.UI/Views/Admin/_Sidebar.cshtml b/PlexRequests.UI/Views/Admin/_Sidebar.cshtml index f679b5fd8..ac6648ad8 100644 --- a/PlexRequests.UI/Views/Admin/_Sidebar.cshtml +++ b/PlexRequests.UI/Views/Admin/_Sidebar.cshtml @@ -1,6 +1,7 @@ 
Request Plex Settings + Authentication CouchPotato Settings Sonarr Settings Sickbeard Settings diff --git a/PlexRequests.sln b/PlexRequests.sln index d490ac073..a528f70e1 100644 --- a/PlexRequests.sln +++ b/PlexRequests.sln @@ -21,6 +21,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Helpers", "PlexRequests.Helpers\PlexRequests.Helpers.csproj", "{1252336D-42A3-482A-804C-836E60173DFA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.UI.Tests", "PlexRequests.UI.Tests\PlexRequests.UI.Tests.csproj", "{A930E2CF-79E2-45F9-B06A-9A719A254CE4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlexRequests.Core.Tests", "PlexRequests.Core.Tests\PlexRequests.Core.Tests.csproj", "{FCFECD5D-47F6-454D-8692-E27A921BE655}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +55,14 @@ Global {1252336D-42A3-482A-804C-836E60173DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU {1252336D-42A3-482A-804C-836E60173DFA}.Release|Any CPU.Build.0 = Release|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A930E2CF-79E2-45F9-B06A-9A719A254CE4}.Release|Any CPU.Build.0 = Release|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FCFECD5D-47F6-454D-8692-E27A921BE655}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE