diff --git a/PlexRequests.Services.Tests/PlexAvailabilityCheckerTests.cs b/PlexRequests.Services.Tests/PlexAvailabilityCheckerTests.cs index 476989215..b5d3f4e10 100644 --- a/PlexRequests.Services.Tests/PlexAvailabilityCheckerTests.cs +++ b/PlexRequests.Services.Tests/PlexAvailabilityCheckerTests.cs @@ -39,6 +39,9 @@ using PlexRequests.Helpers.Exceptions; using PlexRequests.Services.Interfaces; using PlexRequests.Store; using PlexRequests.Helpers; +using PlexRequests.Services.Jobs; +using PlexRequests.Store.Models; +using PlexRequests.Store.Repository; namespace PlexRequests.Services.Tests { @@ -46,19 +49,40 @@ namespace PlexRequests.Services.Tests public class PlexAvailabilityCheckerTests { public IAvailabilityChecker Checker { get; set; } - - //[Test] - //public void IsAvailableWithEmptySettingsTest() - //{ - // var settingsMock = new Mock>(); - // var authMock = new Mock>(); - // var requestMock = new Mock(); - // var plexMock = new Mock(); - // var cacheMock = new Mock(); - // Checker = new PlexAvailabilityChecker(settingsMock.Object, authMock.Object, requestMock.Object, plexMock.Object, cacheMock.Object); - - // Assert.Throws(() => Checker.IsAvailable("title", "2013", null, PlexType.TvShow), "We should be throwing an exception since we cannot talk to the services."); - //} + private Mock> SettingsMock { get; set; } + private Mock> AuthMock { get; set; } + private Mock RequestMock { get; set; } + private Mock PlexMock { get; set; } + private Mock CacheMock { get; set; } + private Mock NotificationMock { get; set; } + private Mock JobRec { get; set; } + private Mock> NotifyUsers { get; set; } + + [SetUp] + public void Setup() + { + SettingsMock = new Mock>(); + AuthMock = new Mock>(); + RequestMock = new Mock(); + PlexMock = new Mock(); + NotificationMock = new Mock(); + CacheMock = new Mock(); + NotifyUsers = new Mock>(); + JobRec = new Mock(); + Checker = new PlexAvailabilityChecker(SettingsMock.Object, AuthMock.Object, RequestMock.Object, PlexMock.Object, CacheMock.Object, NotificationMock.Object, JobRec.Object, NotifyUsers.Object); + + } + + [Test] + public void InvalidSettings() + { + Checker.CheckAndUpdateAll(); + PlexMock.Verify(x => x.GetLibrary(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetAccount(It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetLibrarySections(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetStatus(It.IsAny(), It.IsAny()), Times.Never); + PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); + } //[Test] //public void IsAvailableTest() diff --git a/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj b/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj index b6a3c6dc0..e0bef0232 100644 --- a/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj +++ b/PlexRequests.Services.Tests/PlexRequests.Services.Tests.csproj @@ -36,6 +36,14 @@ 4 + + ..\packages\Common.Logging.3.0.0\lib\net40\Common.Logging.dll + True + + + ..\packages\Common.Logging.Core.3.0.0\lib\net40\Common.Logging.Core.dll + True + ..\packages\Moq.4.2.1510.2205\lib\net40\Moq.dll True @@ -44,6 +52,10 @@ ..\packages\NUnit.3.2.0\lib\net45\nunit.framework.dll True + + ..\packages\Quartz.2.3.3\lib\net40\Quartz.dll + True + @@ -63,7 +75,12 @@ Designer - + + Designer + + + Designer + diff --git a/PlexRequests.Services.Tests/job_scheduling_data_2_0.xsd b/PlexRequests.Services.Tests/job_scheduling_data_2_0.xsd new file mode 100644 index 000000000..d1dabc1a9 --- /dev/null +++ b/PlexRequests.Services.Tests/job_scheduling_data_2_0.xsd @@ -0,0 +1,361 @@ + + + + + + + Root level node + + + + + + Commands to be executed before scheduling the jobs and triggers in this file. + + + + + Directives to be followed while scheduling the jobs and triggers in this file. + + + + + + + + + + + + + + Version of the XML Schema instance + + + + + + + + + + Delete all jobs, if any, in the identified group. "*" can be used to identify all groups. Will also result in deleting all triggers related to the jobs. + + + + + Delete all triggers, if any, in the identified group. "*" can be used to identify all groups. Will also result in deletion of related jobs that are non-durable. + + + + + Delete the identified job if it exists (will also result in deleting all triggers related to it). + + + + + + + + + + + Delete the identified trigger if it exists (will also result in deletion of related jobs that are non-durable). + + + + + + + + + + + + + + + + Whether the existing scheduling data (with same identifiers) will be overwritten. If false, and ignore-duplicates is not false, and jobs or triggers with the same names already exist as those in the file, an error will occur. + + + + + If true (and overwrite-existing-data is false) then any job/triggers encountered in this file that have names that already exist in the scheduler will be ignored, and no error will be produced. + + + + + If true trigger's start time is calculated based on earlier run time instead of fixed value. Trigger's start time must be undefined for this to work. + + + + + + + + Define a JobDetail + + + + + + + + + + + + + + + + + Define a JobDataMap + + + + + + + + + Define a JobDataMap entry + + + + + + + + + + Define a Trigger + + + + + + + + + + + Common Trigger definitions + + + + + + + + + + + + + + + + + + + + + + + Define a SimpleTrigger + + + + + + + + + + + + + + + + + Define a CronTrigger + + + + + + + + + + + + + + + Define a DateIntervalTrigger + + + + + + + + + + + + + + + + Cron expression (see JavaDoc for examples) + + Special thanks to Chris Thatcher (thatcher@butterfly.net) for the regular expression! + + Regular expressions are not my strong point but I believe this is complete, + with the caveat that order for expressions like 3-0 is not legal but will pass, + and month and day names must be capitalized. + If you want to examine the correctness look for the [\s] to denote the + seperation of individual regular expressions. This is how I break them up visually + to examine them: + + SECONDS: + ( + ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) + | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) + | ([\?]) + | ([\*]) + ) [\s] + MINUTES: + ( + ((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?) + | (([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9])) + | ([\?]) + | ([\*]) + ) [\s] + HOURS: + ( + ((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?) + | (([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3])) + | ([\?]) + | ([\*]) + ) [\s] + DAY OF MONTH: + ( + ((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?) + | (([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?) + | (L(-[0-9])?) + | (L(-[1-2][0-9])?) + | (L(-[3][0-1])?) + | (LW) + | ([1-9]W) + | ([1-3][0-9]W) + | ([\?]) + | ([\*]) + )[\s] + MONTH: + ( + ((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?) + | (([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2])) + | (((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?) + | ((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)) + | ([\?]) + | ([\*]) + )[\s] + DAY OF WEEK: + ( + (([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?) + | ([1-7]/([1-7])) + | (((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?) + | ((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?) + | (([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))(L|LW)?) + | (([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?) + | ([\?]) + | ([\*]) + ) + YEAR (OPTIONAL): + ( + [\s]? + ([\*])? + | ((19[7-9][0-9])|(20[0-9][0-9]))? + | (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))? + | ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)? + ) + + + + + + + + + + Number of times to repeat the Trigger (-1 for indefinite) + + + + + + + + + + Simple Trigger Misfire Instructions + + + + + + + + + + + + + + Cron Trigger Misfire Instructions + + + + + + + + + + + Date Interval Trigger Misfire Instructions + + + + + + + + + + + Interval Units + + + + + + + + + + + + + \ No newline at end of file diff --git a/PlexRequests.Services.Tests/packages.config b/PlexRequests.Services.Tests/packages.config index e3f1355a2..50f0bcc7b 100644 --- a/PlexRequests.Services.Tests/packages.config +++ b/PlexRequests.Services.Tests/packages.config @@ -1,5 +1,8 @@  + + + \ No newline at end of file diff --git a/PlexRequests.Services/Jobs/JobRecord.cs b/PlexRequests.Services/Jobs/JobRecord.cs index fd97f785f..2168f5fe9 100644 --- a/PlexRequests.Services/Jobs/JobRecord.cs +++ b/PlexRequests.Services/Jobs/JobRecord.cs @@ -31,7 +31,7 @@ using PlexRequests.Services.Interfaces; using PlexRequests.Store.Models; using PlexRequests.Store.Repository; -namespace PlexRequests.Services +namespace PlexRequests.Services.Jobs { public class JobRecord : IJobRecord { diff --git a/PlexRequests.Services/Jobs/SonarrCacher.cs b/PlexRequests.Services/Jobs/SonarrCacher.cs index 97089da27..e426e8ca5 100644 --- a/PlexRequests.Services/Jobs/SonarrCacher.cs +++ b/PlexRequests.Services/Jobs/SonarrCacher.cs @@ -35,8 +35,6 @@ using PlexRequests.Core; using PlexRequests.Core.SettingModels; using PlexRequests.Helpers; using PlexRequests.Services.Interfaces; -using PlexRequests.Store.Models; -using PlexRequests.Store.Repository; using Quartz; diff --git a/PlexRequests.Services/Jobs/StoreBackup.cs b/PlexRequests.Services/Jobs/StoreBackup.cs index e36f73eb4..68c7db69e 100644 --- a/PlexRequests.Services/Jobs/StoreBackup.cs +++ b/PlexRequests.Services/Jobs/StoreBackup.cs @@ -26,6 +26,7 @@ #endregion using System; using System.IO; +using System.Linq; using NLog; @@ -130,7 +131,18 @@ namespace PlexRequests.Services.Jobs private bool DoWeNeedToBackup(string backupPath) { var files = Directory.GetFiles(backupPath); - //TODO Get the latest file and if it's within an hour of DateTime.Now then don't bother backing up. + var last = files.LastOrDefault(); + if (!string.IsNullOrEmpty(last)) + { + var dt = ParseName(Path.GetFileName(last)); + if (dt < DateTime.Now.AddHours(-1)) + { + return true; + } + return false; + } + + // We don't have a backup return true; } diff --git a/PlexRequests.UI.Tests/UserLoginModuleTests.cs b/PlexRequests.UI.Tests/UserLoginModuleTests.cs index cc4db6843..5072556cc 100644 --- a/PlexRequests.UI.Tests/UserLoginModuleTests.cs +++ b/PlexRequests.UI.Tests/UserLoginModuleTests.cs @@ -25,6 +25,7 @@ // ************************************************************************/ #endregion using System.Collections.Generic; +using System.Threading.Tasks; using Moq; @@ -59,7 +60,7 @@ namespace PlexRequests.UI.Tests AuthMock = new Mock>(); PlexMock = new Mock(); PlexRequestMock = new Mock>(); - PlexRequestMock.Setup(x => x.GetSettings()).Returns(new PlexRequestSettings()); + PlexRequestMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(new PlexRequestSettings())); Bootstrapper = new ConfigurableBootstrapper(with => { with.Module(); @@ -74,7 +75,7 @@ namespace PlexRequests.UI.Tests public void LoginWithoutAuthentication() { var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); @@ -93,7 +94,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); } @@ -102,7 +103,7 @@ namespace PlexRequests.UI.Tests public void LoginWithoutAuthenticationWithEmptyUsername() { var expectedSettings = new AuthenticationSettings { UserAuthentication = false, PlexAuthToken = "abc" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); Bootstrapper.WithSession(new Dictionary()); @@ -119,7 +120,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(false)); - AuthMock.Verify(x => x.GetSettings(), Times.Never); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Never); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); } @@ -139,7 +140,7 @@ namespace PlexRequests.UI.Tests } }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); @@ -158,7 +159,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); } @@ -178,7 +179,7 @@ namespace PlexRequests.UI.Tests } }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); @@ -200,7 +201,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(false)); Assert.That(body.Message, Is.Not.Empty); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); } @@ -227,7 +228,7 @@ namespace PlexRequests.UI.Tests } }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(new PlexAccount()); @@ -249,7 +250,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); } @@ -273,7 +274,7 @@ namespace PlexRequests.UI.Tests user = null }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); @@ -296,7 +297,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(false)); Assert.That(body.Message, Is.Not.Empty); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); } @@ -305,9 +306,9 @@ namespace PlexRequests.UI.Tests public void AttemptToLoginAsDeniedUser() { var expectedSettings = new AuthenticationSettings { UserAuthentication = false, DeniedUsers = "abc", PlexAuthToken = "abc" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); - Bootstrapper.WithSession(new Dictionary()); + Bootstrapper.WithSession(new Dictionary()); var browser = new Browser(Bootstrapper); var result = browser.Post("/userlogin", with => @@ -323,7 +324,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(false)); Assert.That(body.Message, Is.Not.Empty); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); } @@ -357,7 +358,7 @@ namespace PlexRequests.UI.Tests }; var account = new PlexAccount { Username = "Jamie" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(account); PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(new PlexAuthentication { user = new User { username = "Jamie" } }); @@ -377,7 +378,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Never); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Once); } @@ -404,7 +405,7 @@ namespace PlexRequests.UI.Tests var account = new PlexAccount { Username = "Jamie" }; - AuthMock.Setup(x => x.GetSettings()).Returns(expectedSettings); + AuthMock.Setup(x => x.GetSettingsAsync()).Returns(Task.FromResult(expectedSettings)); PlexMock.Setup(x => x.GetUsers(It.IsAny())).Returns(plexFriends); PlexMock.Setup(x => x.SignIn(It.IsAny(), It.IsAny())).Returns(plexAuth); PlexMock.Setup(x => x.GetAccount(It.IsAny())).Returns(account); @@ -426,7 +427,7 @@ namespace PlexRequests.UI.Tests var body = JsonConvert.DeserializeObject(result.Body.AsString()); Assert.That(body.Result, Is.EqualTo(true)); - AuthMock.Verify(x => x.GetSettings(), Times.Once); + AuthMock.Verify(x => x.GetSettingsAsync(), Times.Once); PlexMock.Verify(x => x.SignIn(It.IsAny(), It.IsAny()), Times.Once); PlexMock.Verify(x => x.GetUsers(It.IsAny()), Times.Never); } diff --git a/PlexRequests.UI/Modules/ApprovalModule.cs b/PlexRequests.UI/Modules/ApprovalModule.cs index f9d7018b2..281063364 100644 --- a/PlexRequests.UI/Modules/ApprovalModule.cs +++ b/PlexRequests.UI/Modules/ApprovalModule.cs @@ -27,14 +27,13 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Threading.Tasks; using Nancy; using Nancy.Security; using NLog; -using PlexRequests.Api; + using PlexRequests.Api.Interfaces; using PlexRequests.Core; using PlexRequests.Core.SettingModels;