diff --git a/src/Ombi.Core.Tests/Engine/MovieRequestLimitsTests.cs b/src/Ombi.Core.Tests/Engine/MovieRequestLimitsTests.cs index 3c8953665..6a9eb25cb 100644 --- a/src/Ombi.Core.Tests/Engine/MovieRequestLimitsTests.cs +++ b/src/Ombi.Core.Tests/Engine/MovieRequestLimitsTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Ombi.Core.Authentication; using Ombi.Core.Engine; using Ombi.Core.Models; +using Ombi.Core.Services; using Ombi.Helpers; using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; @@ -24,7 +25,7 @@ namespace Ombi.Core.Tests.Engine { private AutoMocker _mocker; - private MovieRequestEngine _subject; + private RequestLimitService _subject; [SetUp] public void SetUp() @@ -37,14 +38,14 @@ namespace Ombi.Core.Tests.Engine principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); _mocker.Use(principleMock.Object); - _subject = _mocker.CreateInstance(); + _subject = _mocker.CreateInstance(); } [Test] public async Task User_No_MovieLimit_Set() { var user = new OmbiUser(); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result.HasLimit, Is.False); } @@ -59,7 +60,7 @@ namespace Ombi.Core.Tests.Engine - var result = await _subject.GetRemainingRequests(null); + var result = await _subject.GetRemainingMovieRequests(null); Assert.That(result, Is.Null); } @@ -77,7 +78,7 @@ namespace Ombi.Core.Tests.Engine - var result = await _subject.GetRemainingRequests(null); + var result = await _subject.GetRemainingMovieRequests(null); Assert.That(result.HasLimit, Is.False); } @@ -93,7 +94,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(new List().AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -124,7 +125,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -198,7 +199,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -231,7 +232,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -264,7 +265,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -303,7 +304,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -336,7 +337,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -368,7 +369,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -407,7 +408,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -439,7 +440,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -472,7 +473,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -512,7 +513,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingMovieRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) diff --git a/src/Ombi.Core.Tests/Engine/MusicRequestLimitTests.cs b/src/Ombi.Core.Tests/Engine/MusicRequestLimitTests.cs new file mode 100644 index 000000000..ae06cc84e --- /dev/null +++ b/src/Ombi.Core.Tests/Engine/MusicRequestLimitTests.cs @@ -0,0 +1,526 @@ +using MockQueryable.Moq; +using Moq; +using Moq.AutoMock; +using NUnit.Framework; +using Ombi.Core.Authentication; +using Ombi.Core.Engine; +using Ombi.Core.Models; +using Ombi.Core.Services; +using Ombi.Helpers; +using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; +using Ombi.Store.Repository; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Security.Principal; +using System.Threading; +using System.Threading.Tasks; + +namespace Ombi.Core.Tests.Engine +{ + [TestFixture] + public class MusicRequestLimitTests + { + + private AutoMocker _mocker; + private RequestLimitService _subject; + + [SetUp] + public void SetUp() + { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); + _mocker = new AutoMocker(); + var principleMock = new Mock(); + var identityMock = new Mock(); + identityMock.SetupGet(x => x.Name).Returns("Test"); + principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); + _mocker.Use(principleMock.Object); + + _subject = _mocker.CreateInstance(); + } + + [Test] + public async Task User_No_MusicLimit_Set() + { + var user = new OmbiUser(); + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result.HasLimit, Is.False); + } + + [Test] + public async Task No_UserPassedIn_UsernotExist_No_MusicLimit_Set() + { + var user = new OmbiUser(); + + var um = _mocker.GetMock(); + um.SetupGet(x => x.Users).Returns(new List { user }.AsQueryable().BuildMock().Object); + + + + var result = await _subject.GetRemainingMusicRequests(null); + + Assert.That(result, Is.Null); + } + + [Test] + public async Task No_UserPassedIn_No_MusicLimit_Set() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST" + }; + + var um = _mocker.GetMock(); + um.SetupGet(x => x.Users).Returns(new List { user }.AsQueryable().BuildMock().Object); + + + + var result = await _subject.GetRemainingMusicRequests(null); + + Assert.That(result.HasLimit, Is.False); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_No_Requests() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 1 + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(new List().AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(1) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(1) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + Id = "id1" + }; + var yesterday = DateTime.Now.AddDays(-1); + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = yesterday, // Yesterday + } + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(1) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(yesterday.AddDays(7)) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_MultipleRequests() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + Id = "id1" + }; + var yesterday = DateTime.Now.AddDays(-1); + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = yesterday, + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = yesterday.AddDays(-2), + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate =yesterday.AddDays(-3), // Yesterday + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate =yesterday.AddDays(-4), // Yesterday + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate =yesterday.AddDays(-5), // Yesterday + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate =yesterday.AddDays(-6), // Yesterday + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate =yesterday.AddDays(-7), // Yesterday + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = yesterday.AddDays(-8), // Yesterday + }, + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(0) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(yesterday.AddDays(1)) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Daily_NoRequestsToday() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Day, + Id = "id1" + }; + var yesterday = DateTime.Now.AddDays(-1); + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = yesterday, + } + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(2) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Daily_OneRequestsToday() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Day, + Id = "id1" + }; + + var today = DateTime.Now; + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today.AddHours(-1), + } + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(1) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(today.AddDays(1).Date) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Daily_AllRequestsToday() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Day, + Id = "id1" + }; + var today = DateTime.Now; + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today.AddHours(-1), + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today.AddHours(-2), + }, + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(0) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(today.AddDays(1).Date) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Weekly_NoRequests() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Week, + Id = "id1" + }; + var lastWeek = DateTime.Now.FirstDateInWeek().AddDays(-1); // Day before reset + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = lastWeek, + } + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(2) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Weekly_OneRequestsWeek() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Week, + Id = "id1" + }; + var today = DateTime.UtcNow; + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today, + } + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(1) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(today.FirstDateInWeek().AddDays(7).Date) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Weekly_AllRequestsWeek() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Week, + Id = "id1" + }; + var today = DateTime.Now; + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today.AddDays(-1), + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today, + }, + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(0) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(today.FirstDateInWeek().AddDays(7).Date) + ); + } + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Monthly_NoRequests() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Month, + Id = "id1" + }; + var lastWeek = DateTime.Now.AddMonths(-1).AddDays(-1); + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = lastWeek, + } + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(2) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Monthly_OneRequests() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Month, + Id = "id1" + }; + var today = DateTime.Now; + var firstDayOfMonth = new DateTime(today.Year, today.Month, 1); + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today, + } + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(1) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(firstDayOfMonth.AddMonths(1).Date) + ); + } + + [Test] + public async Task UserPassedIn_MusicLimit_Set_Limit_Monthly_AllRequests() + { + var user = new OmbiUser + { + NormalizedUserName = "TEST", + MusicRequestLimit = 2, + MusicRequestLimitType = RequestLimitType.Month, + Id = "id1" + }; + var today = DateTime.Now; + var firstDayOfMonth = new DateTime(today.Year, today.Month, 1); + var log = new List + { + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today.AddDays(-1), + }, + new RequestLog + { + UserId = "id1", + RequestType = RequestType.Album, + RequestDate = today, + }, + }; + var repoMock = _mocker.GetMock>(); + repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); + + var result = await _subject.GetRemainingMusicRequests(user); + + Assert.That(result, Is.InstanceOf() + .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) + .And.Property(nameof(RequestQuotaCountModel.Limit)).EqualTo(2) + .And.Property(nameof(RequestQuotaCountModel.Remaining)).EqualTo(0) + .And.Property(nameof(RequestQuotaCountModel.NextRequest)).EqualTo(firstDayOfMonth.AddMonths(1).Date) + ); + } + } +} diff --git a/src/Ombi.Core.Tests/Engine/TvRequestLimitsTests.cs b/src/Ombi.Core.Tests/Engine/TvRequestLimitsTests.cs index 3882cfb25..c9fb8311b 100644 --- a/src/Ombi.Core.Tests/Engine/TvRequestLimitsTests.cs +++ b/src/Ombi.Core.Tests/Engine/TvRequestLimitsTests.cs @@ -5,6 +5,7 @@ using NUnit.Framework; using Ombi.Core.Authentication; using Ombi.Core.Engine; using Ombi.Core.Models; +using Ombi.Core.Services; using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; using Ombi.Store.Repository; @@ -21,7 +22,7 @@ namespace Ombi.Core.Tests.Engine { private AutoMocker _mocker; - private TvRequestEngine _subject; + private RequestLimitService _subject; [SetUp] public void SetUp() @@ -33,14 +34,14 @@ namespace Ombi.Core.Tests.Engine principleMock.SetupGet(x => x.Identity).Returns(identityMock.Object); _mocker.Use(principleMock.Object); - _subject = _mocker.CreateInstance(); + _subject = _mocker.CreateInstance(); } [Test] public async Task User_No_TvLimit_Set() { var user = new OmbiUser(); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result.HasLimit, Is.False); } @@ -55,7 +56,7 @@ namespace Ombi.Core.Tests.Engine - var result = await _subject.GetRemainingRequests(null); + var result = await _subject.GetRemainingTvRequests(null); Assert.That(result, Is.Null); } @@ -73,7 +74,7 @@ namespace Ombi.Core.Tests.Engine - var result = await _subject.GetRemainingRequests(null); + var result = await _subject.GetRemainingTvRequests(null); Assert.That(result.HasLimit, Is.False); } @@ -89,7 +90,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(new List().AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -120,7 +121,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -202,7 +203,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -236,7 +237,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -269,7 +270,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -310,7 +311,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -351,7 +352,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -385,7 +386,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -418,7 +419,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -459,7 +460,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -500,7 +501,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -534,7 +535,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -567,7 +568,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -608,7 +609,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) @@ -649,7 +650,7 @@ namespace Ombi.Core.Tests.Engine var repoMock = _mocker.GetMock>(); repoMock.Setup(x => x.GetAll()).Returns(log.AsQueryable().BuildMock().Object); - var result = await _subject.GetRemainingRequests(user); + var result = await _subject.GetRemainingTvRequests(user); Assert.That(result, Is.InstanceOf() .With.Property(nameof(RequestQuotaCountModel.HasLimit)).EqualTo(true) diff --git a/src/Ombi.Core/Engine/IMusicRequestEngine.cs b/src/Ombi.Core/Engine/IMusicRequestEngine.cs index 306d5c477..4dbb3b16a 100644 --- a/src/Ombi.Core/Engine/IMusicRequestEngine.cs +++ b/src/Ombi.Core/Engine/IMusicRequestEngine.cs @@ -22,7 +22,6 @@ namespace Ombi.Core.Engine Task RequestAlbum(MusicAlbumRequestViewModel model); Task> SearchAlbumRequest(string search); Task UserHasRequest(string userId); - Task GetRemainingRequests(OmbiUser user = null); Task> GetRequestsByStatus(int count, int position, string sort, string sortOrder, RequestStatus available); Task> GetRequests(int count, int position, string sort, string sortOrder); } diff --git a/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs b/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs index f4eeb6fc3..44278753f 100644 --- a/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs +++ b/src/Ombi.Core/Engine/Interfaces/IRequestEngine.cs @@ -24,7 +24,6 @@ namespace Ombi.Core.Engine.Interfaces Task GetTotal(); Task UnSubscribeRequest(int requestId, RequestType type); Task SubscribeToRequest(int requestId, RequestType type); - Task GetRemainingRequests(OmbiUser user = null); Task ReProcessRequest(int requestId, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/MovieRequestEngine.cs b/src/Ombi.Core/Engine/MovieRequestEngine.cs index 1601254a2..bf694a262 100644 --- a/src/Ombi.Core/Engine/MovieRequestEngine.cs +++ b/src/Ombi.Core/Engine/MovieRequestEngine.cs @@ -753,98 +753,5 @@ namespace Ombi.Core.Engine return new RequestEngineResult { Result = true, Message = $"{movieName} has been successfully added!", RequestId = model.Id }; } - - public async Task GetRemainingRequests(OmbiUser user) - { - if (user == null) - { - user = await GetUser(); - - // If user is still null after attempting to get the logged in user, return null. - if (user == null) - { - return null; - } - } - - int limit = user.MovieRequestLimit ?? 0; - - if (limit <= 0) - { - return new RequestQuotaCountModel() - { - HasLimit = false, - Limit = 0, - Remaining = 0, - NextRequest = DateTime.Now, - }; - } - - IQueryable log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.Movie); - - - int count = 0; - DateTime oldestRequestedAt = DateTime.Now; - DateTime nextRequest = DateTime.Now; - - if (!user.MovieRequestLimitType.HasValue) - { - count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)); - - oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - - return new RequestQuotaCountModel() - { - HasLimit = true, - Limit = limit, - Remaining = count < 0 ? 0 : count, - NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc), - }; - } - - switch (user.MovieRequestLimitType) - { - case RequestLimitType.Day: - count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.Date); - oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - nextRequest = oldestRequestedAt.AddDays(1).Date; - break; - case RequestLimitType.Week: - var fdow = DateTime.UtcNow.FirstDateInWeek(); - count = limit - await log.CountAsync(x => x.RequestDate >= fdow); - oldestRequestedAt = await log.Where(x => x.RequestDate >= fdow) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - nextRequest = fdow.AddDays(7).Date; - break; - case RequestLimitType.Month: - var now = DateTime.UtcNow; - var firstDayOfMonth = new DateTime(now.Year, now.Month, 1); - count = limit - await log.CountAsync(x => x.RequestDate >= firstDayOfMonth); - oldestRequestedAt = await log.Where(x => x.RequestDate >= firstDayOfMonth) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - nextRequest = firstDayOfMonth.AddMonths(1).Date; - break; - default: - break; - } - - return new RequestQuotaCountModel() - { - HasLimit = true, - Limit = limit, - Remaining = count < 0 ? 0 : count, - NextRequest = DateTime.SpecifyKind(nextRequest, DateTimeKind.Utc), - }; - } } } \ No newline at end of file diff --git a/src/Ombi.Core/Engine/MusicRequestEngine.cs b/src/Ombi.Core/Engine/MusicRequestEngine.cs index 032b2ae7d..d0a9cc5d7 100644 --- a/src/Ombi.Core/Engine/MusicRequestEngine.cs +++ b/src/Ombi.Core/Engine/MusicRequestEngine.cs @@ -435,49 +435,6 @@ namespace Ombi.Core.Engine Result = true }; } - public async Task GetRemainingRequests(OmbiUser user) - { - if (user == null) - { - user = await GetUser(); - - // If user is still null after attempting to get the logged in user, return null. - if (user == null) - { - return null; - } - } - - int limit = user.MusicRequestLimit ?? 0; - - if (limit <= 0) - { - return new RequestQuotaCountModel() - { - HasLimit = false, - Limit = 0, - Remaining = 0, - NextRequest = DateTime.Now, - }; - } - - IQueryable log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.Album); - - int count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)); - - DateTime oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - - return new RequestQuotaCountModel() - { - HasLimit = true, - Limit = limit, - Remaining = count, - NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc), - }; - } public async Task MarkAvailable(int modelId) { diff --git a/src/Ombi.Core/Engine/TvRequestEngine.cs b/src/Ombi.Core/Engine/TvRequestEngine.cs index c5c49bf83..d0d139d0c 100644 --- a/src/Ombi.Core/Engine/TvRequestEngine.cs +++ b/src/Ombi.Core/Engine/TvRequestEngine.cs @@ -955,123 +955,7 @@ namespace Ombi.Core.Engine return new RequestEngineResult { Result = true, RequestId = model.Id }; } - public async Task GetRemainingRequests(OmbiUser user) - { - if (user == null) - { - user = await GetUser(); - - // If user is still null after attempting to get the logged in user, return null. - if (user == null) - { - return null; - } - } - - int limit = user.EpisodeRequestLimit ?? 0; - - if (limit <= 0) - { - return new RequestQuotaCountModel() - { - HasLimit = false, - Limit = 0, - Remaining = 0, - NextRequest = DateTime.Now, - }; - } - - IQueryable log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.TvShow); - - int count = 0; - DateTime oldestRequestedAt = DateTime.Now; - DateTime nextRequest = DateTime.Now; - - - IQueryable filteredLog; - int zeroEpisodeCount; - int episodeCount; - - if (!user.EpisodeRequestLimitType.HasValue) - { - filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)); - // Needed, due to a bug which would cause all episode counts to be 0 - zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); - - episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); - - count = limit - (zeroEpisodeCount + episodeCount); - - oldestRequestedAt = await log - .Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - - return new RequestQuotaCountModel() - { - HasLimit = true, - Limit = limit, - Remaining = count < 0 ? 0 : count, - NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc), - }; - } - - switch (user.EpisodeRequestLimitType) - { - case RequestLimitType.Day: - - filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.Date); - // Needed, due to a bug which would cause all episode counts to be 0 - zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); - episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); - count = limit - (zeroEpisodeCount + episodeCount); - - oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - nextRequest = oldestRequestedAt.AddDays(1); - break; - case RequestLimitType.Week: - - filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddDays(-7)); - // Needed, due to a bug which would cause all episode counts to be 0 - zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); - episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); - count = limit - (zeroEpisodeCount + episodeCount); - - oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddDays(-7)) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - nextRequest = oldestRequestedAt.AddDays(7); - break; - case RequestLimitType.Month: - filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddMonths(-1)); - // Needed, due to a bug which would cause all episode counts to be 0 - zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); - episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); - count = limit - (zeroEpisodeCount + episodeCount); - - oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddMonths(-1)) - .OrderBy(x => x.RequestDate) - .Select(x => x.RequestDate) - .FirstOrDefaultAsync(); - nextRequest = oldestRequestedAt.AddMonths(1); - break; - default: - break; - } - - return new RequestQuotaCountModel() - { - HasLimit = true, - Limit = limit, - Remaining = count < 0 ? 0 : count, - NextRequest = DateTime.SpecifyKind(nextRequest, DateTimeKind.Utc), - }; - } + public async Task UpdateAdvancedOptions(MediaAdvancedOptions options) { diff --git a/src/Ombi.Core/Services/RequestLimitService.cs b/src/Ombi.Core/Services/RequestLimitService.cs new file mode 100644 index 000000000..2872e69dd --- /dev/null +++ b/src/Ombi.Core/Services/RequestLimitService.cs @@ -0,0 +1,293 @@ +using Microsoft.EntityFrameworkCore; +using Ombi.Core.Authentication; +using Ombi.Core.Engine.Interfaces; +using Ombi.Core.Models; +using Ombi.Core.Rule.Interfaces; +using Ombi.Helpers; +using Ombi.Store.Entities; +using Ombi.Store.Entities.Requests; +using Ombi.Store.Repository; +using System; +using System.Linq; +using System.Security.Principal; +using System.Threading.Tasks; + +namespace Ombi.Core.Services +{ + public interface IRequestLimitService + { + Task GetRemainingMovieRequests(OmbiUser user = default); + Task GetRemainingTvRequests(OmbiUser user = default); + Task GetRemainingMusicRequests(OmbiUser user = default); + } + public class RequestLimitService : BaseEngine, IRequestLimitService + { + private readonly IRepository _requestLog; + + public RequestLimitService(IPrincipal user, OmbiUserManager um, IRuleEvaluator rules, IRepository rl) : base(user, um, rules) + { + _requestLog = rl; + } + + public async Task GetRemainingMovieRequests(OmbiUser user) + { + if (user == null) + { + user = await GetUser(); + + // If user is still null after attempting to get the logged in user, return null. + if (user == null) + { + return null; + } + } + + int limit = user.MovieRequestLimit ?? 0; + + if (limit <= 0) + { + return new RequestQuotaCountModel() + { + HasLimit = false, + Limit = 0, + Remaining = 0, + NextRequest = DateTime.Now, + }; + } + + IQueryable log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.Movie); + + if (!user.MovieRequestLimitType.HasValue) + { + var count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)); + + var oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + + return new RequestQuotaCountModel() + { + HasLimit = true, + Limit = limit, + Remaining = count < 0 ? 0 : count, + NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc), + }; + } + + + return await CalculateBasicRemaingRequests(user, limit, user.MovieRequestLimitType ?? RequestLimitType.Day, log); + } + + public async Task GetRemainingMusicRequests(OmbiUser user) + { + if (user == null) + { + user = await GetUser(); + + // If user is still null after attempting to get the logged in user, return null. + if (user == null) + { + return null; + } + } + + int limit = user.MusicRequestLimit ?? 0; + + if (limit <= 0) + { + return new RequestQuotaCountModel() + { + HasLimit = false, + Limit = 0, + Remaining = 0, + NextRequest = DateTime.Now, + }; + } + + IQueryable log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.Album); + + // Hisoric Limits + if (!user.MusicRequestLimitType.HasValue) + { + var oldcount = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)); + + var oldestRequestedAtOld = await log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + + return new RequestQuotaCountModel() + { + HasLimit = true, + Limit = limit, + Remaining = oldcount < 0 ? 0 : oldcount, + NextRequest = DateTime.SpecifyKind(oldestRequestedAtOld.AddDays(7), DateTimeKind.Utc), + }; + } + + return await CalculateBasicRemaingRequests(user, limit, user.MusicRequestLimitType ?? RequestLimitType.Day, log); + } + + private static async Task CalculateBasicRemaingRequests(OmbiUser user, int limit, RequestLimitType type, IQueryable log) + { + int count = 0; + DateTime oldestRequestedAt = DateTime.Now; + DateTime nextRequest = DateTime.Now; + switch (type) + { + case RequestLimitType.Day: + count = limit - await log.CountAsync(x => x.RequestDate >= DateTime.UtcNow.Date); + oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + nextRequest = oldestRequestedAt.AddDays(1).Date; + break; + case RequestLimitType.Week: + var fdow = DateTime.UtcNow.FirstDateInWeek(); + count = limit - await log.CountAsync(x => x.RequestDate >= fdow); + oldestRequestedAt = await log.Where(x => x.RequestDate >= fdow) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + nextRequest = fdow.AddDays(7).Date; + break; + case RequestLimitType.Month: + var now = DateTime.UtcNow; + var firstDayOfMonth = new DateTime(now.Year, now.Month, 1); + count = limit - await log.CountAsync(x => x.RequestDate >= firstDayOfMonth); + oldestRequestedAt = await log.Where(x => x.RequestDate >= firstDayOfMonth) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + nextRequest = firstDayOfMonth.AddMonths(1).Date; + break; + } + + return new RequestQuotaCountModel() + { + HasLimit = true, + Limit = limit, + Remaining = count < 0 ? 0 : count, + NextRequest = DateTime.SpecifyKind(nextRequest, DateTimeKind.Utc), + }; + } + + public async Task GetRemainingTvRequests(OmbiUser user) + { + if (user == null) + { + user = await GetUser(); + + // If user is still null after attempting to get the logged in user, return null. + if (user == null) + { + return null; + } + } + + int limit = user.EpisodeRequestLimit ?? 0; + + if (limit <= 0) + { + return new RequestQuotaCountModel() + { + HasLimit = false, + Limit = 0, + Remaining = 0, + NextRequest = DateTime.Now, + }; + } + + IQueryable log = _requestLog.GetAll().Where(x => x.UserId == user.Id && x.RequestType == RequestType.TvShow); + + int count = 0; + DateTime oldestRequestedAt = DateTime.Now; + DateTime nextRequest = DateTime.Now; + + + IQueryable filteredLog; + int zeroEpisodeCount; + int episodeCount; + + if (!user.EpisodeRequestLimitType.HasValue) + { + filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)); + // Needed, due to a bug which would cause all episode counts to be 0 + zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); + + episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); + + count = limit - (zeroEpisodeCount + episodeCount); + + oldestRequestedAt = await log + .Where(x => x.RequestDate >= DateTime.UtcNow.AddDays(-7)) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + + return new RequestQuotaCountModel() + { + HasLimit = true, + Limit = limit, + Remaining = count < 0 ? 0 : count, + NextRequest = DateTime.SpecifyKind(oldestRequestedAt.AddDays(7), DateTimeKind.Utc), + }; + } + + switch (user.EpisodeRequestLimitType) + { + case RequestLimitType.Day: + + filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.Date); + // Needed, due to a bug which would cause all episode counts to be 0 + zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); + episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); + count = limit - (zeroEpisodeCount + episodeCount); + + oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + nextRequest = oldestRequestedAt.AddDays(1); + break; + case RequestLimitType.Week: + + filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddDays(-7)); + // Needed, due to a bug which would cause all episode counts to be 0 + zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); + episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); + count = limit - (zeroEpisodeCount + episodeCount); + + oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddDays(-7)) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + nextRequest = oldestRequestedAt.AddDays(7); + break; + case RequestLimitType.Month: + filteredLog = log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddMonths(-1)); + // Needed, due to a bug which would cause all episode counts to be 0 + zeroEpisodeCount = await filteredLog.Where(x => x.EpisodeCount == 0).Select(x => x.EpisodeCount).CountAsync(); + episodeCount = await filteredLog.Where(x => x.EpisodeCount != 0).Select(x => x.EpisodeCount).SumAsync(); + count = limit - (zeroEpisodeCount + episodeCount); + + oldestRequestedAt = await log.Where(x => x.RequestDate >= DateTime.UtcNow.Date.AddMonths(-1)) + .OrderBy(x => x.RequestDate) + .Select(x => x.RequestDate) + .FirstOrDefaultAsync(); + nextRequest = oldestRequestedAt.AddMonths(1); + break; + } + + return new RequestQuotaCountModel() + { + HasLimit = true, + Limit = limit, + Remaining = count < 0 ? 0 : count, + NextRequest = DateTime.SpecifyKind(nextRequest, DateTimeKind.Utc), + }; + } + } +} diff --git a/src/Ombi.DependencyInjection/IocExtensions.cs b/src/Ombi.DependencyInjection/IocExtensions.cs index 62686deec..bbe4bcb7a 100644 --- a/src/Ombi.DependencyInjection/IocExtensions.cs +++ b/src/Ombi.DependencyInjection/IocExtensions.cs @@ -69,6 +69,7 @@ using Ombi.Api.CloudService; using Ombi.Api.RottenTomatoes; using System.Net.Http; using Microsoft.Extensions.Logging; +using Ombi.Core.Services; namespace Ombi.DependencyInjection { @@ -88,34 +89,34 @@ namespace Ombi.DependencyInjection public static void RegisterEngines(this IServiceCollection services) { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } public static void RegisterEnginesV2(this IServiceCollection services) { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } public static void RegisterHttp(this IServiceCollection services) @@ -138,40 +139,40 @@ namespace Ombi.DependencyInjection public static void RegisterApi(this IServiceCollection services) { services.AddScoped(s => new Api.Api(s.GetRequiredService>(), s.GetRequiredService().CreateClient("OmbiClient"))); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } public static void RegisterStore(this IServiceCollection services) { @@ -201,26 +202,27 @@ namespace Ombi.DependencyInjection } public static void RegisterServices(this IServiceCollection services) { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddScoped(); + services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } public static void RegisterJobs(this IServiceCollection services) @@ -228,35 +230,35 @@ namespace Ombi.DependencyInjection services.AddSingleton(); services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); } } } diff --git a/src/Ombi/Controllers/V1/IdentityController.cs b/src/Ombi/Controllers/V1/IdentityController.cs index ca10902b8..c010f0c02 100644 --- a/src/Ombi/Controllers/V1/IdentityController.cs +++ b/src/Ombi/Controllers/V1/IdentityController.cs @@ -17,6 +17,7 @@ using Ombi.Core.Engine; using Ombi.Core.Engine.Interfaces; using Ombi.Core.Helpers; using Ombi.Core.Models.UI; +using Ombi.Core.Services; using Ombi.Core.Settings; using Ombi.Core.Settings.Models.External; using Ombi.Helpers; @@ -68,6 +69,7 @@ namespace Ombi.Controllers.V1 ITvRequestEngine tvRequestEngine, IMusicRequestEngine musicEngine, IUserDeletionEngine deletionEngine, + IRequestLimitService requestLimitService, ICacheService cacheService) { UserManager = user; @@ -96,11 +98,13 @@ namespace Ombi.Controllers.V1 _userQualityProfiles = userProfiles; MusicRequestEngine = musicEngine; _deletionEngine = deletionEngine; + _requestLimitService = requestLimitService; _cacheService = cacheService; } private OmbiUserManager UserManager { get; } private readonly IUserDeletionEngine _deletionEngine; + private readonly IRequestLimitService _requestLimitService; private readonly ICacheService _cacheService; private RoleManager RoleManager { get; } @@ -422,17 +426,17 @@ namespace Ombi.Controllers.V1 if (vm.EpisodeRequestLimit > 0) { - vm.EpisodeRequestQuota = await TvRequestEngine.GetRemainingRequests(user); + vm.EpisodeRequestQuota = await _requestLimitService.GetRemainingTvRequests(user); } if (vm.MovieRequestLimit > 0) { - vm.MovieRequestQuota = await MovieRequestEngine.GetRemainingRequests(user); + vm.MovieRequestQuota = await _requestLimitService.GetRemainingMovieRequests(user); } if (vm.MusicRequestLimit > 0) { - vm.MusicRequestQuota = await MusicRequestEngine.GetRemainingRequests(user); + vm.MusicRequestQuota = await _requestLimitService.GetRemainingMusicRequests(user); } // Get the quality profiles diff --git a/src/Ombi/Controllers/V1/MusicRequestController.cs b/src/Ombi/Controllers/V1/MusicRequestController.cs index 2b16d3651..df9d2f406 100644 --- a/src/Ombi/Controllers/V1/MusicRequestController.cs +++ b/src/Ombi/Controllers/V1/MusicRequestController.cs @@ -10,6 +10,7 @@ using Ombi.Core.Engine; using Ombi.Core.Models; using Ombi.Core.Models.Requests; using Ombi.Core.Models.UI; +using Ombi.Core.Services; using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; using ILogger = Microsoft.Extensions.Logging.ILogger; @@ -22,16 +23,18 @@ namespace Ombi.Controllers.V1 [ApiController] public class MusicRequestController : ControllerBase { - public MusicRequestController(IMusicRequestEngine engine, IVoteEngine voteEngine, ILogger log) + public MusicRequestController(IMusicRequestEngine engine, IVoteEngine voteEngine, ILogger log, IRequestLimitService requestLimitService) { _engine = engine; _voteEngine = voteEngine; _log = log; + _requestLimitService = requestLimitService; } private readonly IMusicRequestEngine _engine; private readonly IVoteEngine _voteEngine; private readonly ILogger _log; + private readonly IRequestLimitService _requestLimitService; /// /// Gets album requests. @@ -169,7 +172,7 @@ namespace Ombi.Controllers.V1 [HttpGet("remaining")] public async Task GetRemainingMusicRequests() { - return await _engine.GetRemainingRequests(); + return await _requestLimitService.GetRemainingMusicRequests(); } private string GetApiAlias() { diff --git a/src/Ombi/Controllers/V1/RequestController.cs b/src/Ombi/Controllers/V1/RequestController.cs index 206391b07..961969b6f 100644 --- a/src/Ombi/Controllers/V1/RequestController.cs +++ b/src/Ombi/Controllers/V1/RequestController.cs @@ -11,6 +11,7 @@ using Ombi.Core.Engine.Interfaces; using Ombi.Core.Models; using Ombi.Core.Models.Requests; using Ombi.Core.Models.UI; +using Ombi.Core.Services; using Ombi.Models; using Ombi.Store.Entities; using Ombi.Store.Entities.Requests; @@ -23,13 +24,16 @@ namespace Ombi.Controllers.V1 [ApiController] public class RequestController : ControllerBase { + private readonly IRequestLimitService _requestLimitService; + public RequestController(IMovieRequestEngine engine, ITvRequestEngine tvRequestEngine, IVoteEngine vote, - ILogger log) + ILogger log, IRequestLimitService requestLimitService) { MovieRequestEngine = engine; TvRequestEngine = tvRequestEngine; VoteEngine = vote; Log = log; + _requestLimitService = requestLimitService; } private IMovieRequestEngine MovieRequestEngine { get; } @@ -523,7 +527,7 @@ namespace Ombi.Controllers.V1 [HttpGet("movie/remaining")] public async Task GetRemainingMovieRequests() { - return await MovieRequestEngine.GetRemainingRequests(); + return await _requestLimitService.GetRemainingMovieRequests(); } /// @@ -532,7 +536,7 @@ namespace Ombi.Controllers.V1 [HttpGet("tv/remaining")] public async Task GetRemainingTvRequests() { - return await TvRequestEngine.GetRemainingRequests(); + return await _requestLimitService.GetRemainingTvRequests(); } private string GetApiAlias()