feat(discover): Added a new API to query recently requested content

This commit is contained in:
tidusjar 2021-11-08 22:44:06 +00:00
commit 7d3be883d6
7 changed files with 326 additions and 1 deletions

View file

@ -0,0 +1,170 @@
using AutoFixture;
using MockQueryable.Moq;
using Moq;
using Moq.AutoMock;
using NUnit.Framework;
using Ombi.Core.Models.Requests;
using Ombi.Core.Services;
using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
using Ombi.Store.Entities.Requests;
using Ombi.Store.Repository.Requests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Ombi.Core.Tests.Services
{
[TestFixture]
public class RecentlyRequestedServiceTests
{
private AutoMocker _mocker;
private RecentlyRequestedService _subject;
private Fixture _fixture;
[SetUp]
public void Setup()
{
_fixture = new Fixture();
_fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => _fixture.Behaviors.Remove(b));
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
_mocker = new AutoMocker();
_subject = _mocker.CreateInstance<RecentlyRequestedService>();
}
[Test]
public async Task GetRecentlyRequested_Movies()
{
_mocker.Setup<ISettingsService<CustomizationSettings>, Task<CustomizationSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new CustomizationSettings());
var releaseDate = new DateTime(2019, 01, 01);
var requestDate = DateTime.Now;
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id = 1,
Approved = true,
Available = true,
ReleaseDate = releaseDate,
Title = "title",
Overview = "overview",
RequestedDate = requestDate,
RequestedUser = new Store.Entities.OmbiUser
{
UserName = "a"
},
RequestedUserId = "b",
}
};
var albums = new List<AlbumRequest>();
var chilRequests = new List<ChildRequests>();
_mocker.Setup<IMovieRequestRepository, IQueryable<MovieRequests>>(x => x.GetAll()).Returns(movies.AsQueryable().BuildMock().Object);
_mocker.Setup<IMusicRequestRepository, IQueryable<AlbumRequest>>(x => x.GetAll()).Returns(albums.AsQueryable().BuildMock().Object);
_mocker.Setup<ITvRequestRepository, IQueryable<ChildRequests>>(x => x.GetChild()).Returns(chilRequests.AsQueryable().BuildMock().Object);
var result = await _subject.GetRecentlyRequested(CancellationToken.None);
Assert.That(result.Count, Is.EqualTo(1));
Assert.That(result.First(), Is.InstanceOf<RecentlyRequestedModel>()
.With.Property(nameof(RecentlyRequestedModel.RequestId)).EqualTo(1)
.With.Property(nameof(RecentlyRequestedModel.Approved)).EqualTo(true)
.With.Property(nameof(RecentlyRequestedModel.Available)).EqualTo(true)
.With.Property(nameof(RecentlyRequestedModel.Title)).EqualTo("title")
.With.Property(nameof(RecentlyRequestedModel.Overview)).EqualTo("overview")
.With.Property(nameof(RecentlyRequestedModel.RequestDate)).EqualTo(requestDate)
.With.Property(nameof(RecentlyRequestedModel.ReleaseDate)).EqualTo(releaseDate)
.With.Property(nameof(RecentlyRequestedModel.Type)).EqualTo(RequestType.Movie)
);
}
[Test]
public async Task GetRecentlyRequested_Movies_HideAvailable()
{
_mocker.Setup<ISettingsService<CustomizationSettings>, Task<CustomizationSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new CustomizationSettings() { HideAvailableRecentlyRequested = true });
var releaseDate = new DateTime(2019, 01, 01);
var requestDate = DateTime.Now;
var movies = new List<MovieRequests>
{
new MovieRequests
{
Id = 1,
Approved = true,
Available = true,
ReleaseDate = releaseDate,
Title = "title",
Overview = "overview",
RequestedDate = requestDate,
RequestedUser = new Store.Entities.OmbiUser
{
UserName = "a"
},
RequestedUserId = "b",
},
new MovieRequests
{
Id = 1,
Approved = true,
Available = false,
ReleaseDate = releaseDate,
Title = "title2",
Overview = "overview2",
RequestedDate = requestDate,
RequestedUser = new Store.Entities.OmbiUser
{
UserName = "a"
},
RequestedUserId = "b",
}
};
var albums = new List<AlbumRequest>();
var chilRequests = new List<ChildRequests>();
_mocker.Setup<IMovieRequestRepository, IQueryable<MovieRequests>>(x => x.GetAll()).Returns(movies.AsQueryable().BuildMock().Object);
_mocker.Setup<IMusicRequestRepository, IQueryable<AlbumRequest>>(x => x.GetAll()).Returns(albums.AsQueryable().BuildMock().Object);
_mocker.Setup<ITvRequestRepository, IQueryable<ChildRequests>>(x => x.GetChild()).Returns(chilRequests.AsQueryable().BuildMock().Object);
var result = await _subject.GetRecentlyRequested(CancellationToken.None);
Assert.That(result.Count, Is.EqualTo(1));
Assert.That(result.First(), Is.InstanceOf<RecentlyRequestedModel>()
.With.Property(nameof(RecentlyRequestedModel.RequestId)).EqualTo(1)
.With.Property(nameof(RecentlyRequestedModel.Approved)).EqualTo(true)
.With.Property(nameof(RecentlyRequestedModel.Available)).EqualTo(false)
.With.Property(nameof(RecentlyRequestedModel.Title)).EqualTo("title2")
.With.Property(nameof(RecentlyRequestedModel.Overview)).EqualTo("overview2")
.With.Property(nameof(RecentlyRequestedModel.RequestDate)).EqualTo(requestDate)
.With.Property(nameof(RecentlyRequestedModel.ReleaseDate)).EqualTo(releaseDate)
.With.Property(nameof(RecentlyRequestedModel.Type)).EqualTo(RequestType.Movie)
);
}
[Test]
public async Task GetRecentlyRequested()
{
_mocker.Setup<ISettingsService<CustomizationSettings>, Task<CustomizationSettings>>(x => x.GetSettingsAsync())
.ReturnsAsync(new CustomizationSettings());
var releaseDate = new DateTime(2019, 01, 01);
var requestDate = DateTime.Now;
var movies = _fixture.CreateMany<MovieRequests>(10);
var albums = _fixture.CreateMany<AlbumRequest>(10);
var chilRequests = _fixture.CreateMany<ChildRequests>(10);
_mocker.Setup<IMovieRequestRepository, IQueryable<MovieRequests>>(x => x.GetAll()).Returns(movies.AsQueryable().BuildMock().Object);
_mocker.Setup<IMusicRequestRepository, IQueryable<AlbumRequest>>(x => x.GetAll()).Returns(albums.AsQueryable().BuildMock().Object);
_mocker.Setup<ITvRequestRepository, IQueryable<ChildRequests>>(x => x.GetChild()).Returns(chilRequests.AsQueryable().BuildMock().Object);
var result = await _subject.GetRecentlyRequested(CancellationToken.None);
Assert.That(result.Count, Is.EqualTo(21));
}
}
}

View file

@ -0,0 +1,20 @@
using Ombi.Store.Entities;
using System;
namespace Ombi.Core.Models.Requests
{
public class RecentlyRequestedModel
{
public int RequestId { get; set; }
public RequestType Type { get; set; }
public string UserId { get; set; }
public string Username { get; set; }
public bool Available { get; set; }
public bool TvPartiallyAvailable { get; set; }
public DateTime RequestDate { get; set; }
public string Title { get; set; }
public string Overview { get; set; }
public DateTime ReleaseDate { get; set; }
public bool Approved { get; set; }
}
}

View file

@ -0,0 +1,12 @@
using Ombi.Core.Models.Requests;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Ombi.Core.Services
{
public interface IRecentlyRequestedService
{
Task<IEnumerable<RecentlyRequestedModel>> GetRecentlyRequested(CancellationToken cancellationToken);
}
}

View file

@ -0,0 +1,111 @@
using Microsoft.EntityFrameworkCore;
using Ombi.Core.Models.Requests;
using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
using Ombi.Store.Entities;
using Ombi.Store.Repository.Requests;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Ombi.Core.Services
{
public class RecentlyRequestedService : IRecentlyRequestedService
{
private readonly IMovieRequestRepository _movieRequestRepository;
private readonly ITvRequestRepository _tvRequestRepository;
private readonly IMusicRequestRepository _musicRequestRepository;
private readonly ISettingsService<CustomizationSettings> _customizationSettings;
private const int AmountToTake = 7;
public RecentlyRequestedService(
IMovieRequestRepository movieRequestRepository,
ITvRequestRepository tvRequestRepository,
IMusicRequestRepository musicRequestRepository,
ISettingsService<CustomizationSettings> customizationSettings)
{
_movieRequestRepository = movieRequestRepository;
_tvRequestRepository = tvRequestRepository;
_musicRequestRepository = musicRequestRepository;
_customizationSettings = customizationSettings;
}
public async Task<IEnumerable<RecentlyRequestedModel>> GetRecentlyRequested(CancellationToken cancellationToken)
{
var customizationSettingsTask = _customizationSettings.GetSettingsAsync();
var recentMovieRequests = _movieRequestRepository.GetAll().Include(x => x.RequestedUser).OrderByDescending(x => x.RequestedDate).Take(AmountToTake);
var recentTvRequests = _tvRequestRepository.GetChild().Include(x => x.RequestedUser).Include(x => x.ParentRequest).OrderByDescending(x => x.RequestedDate).Take(AmountToTake);
var recentMusicRequests = _musicRequestRepository.GetAll().Include(x => x.RequestedUser).OrderByDescending(x => x.RequestedDate).Take(AmountToTake);
var settings = await customizationSettingsTask;
if (settings.HideAvailableRecentlyRequested)
{
recentMovieRequests = recentMovieRequests.Where(x => !x.Available);
recentTvRequests = recentTvRequests.Where(x => !x.Available);
recentMusicRequests = recentMusicRequests.Where(x => !x.Available);
}
var model = new List<RecentlyRequestedModel>();
foreach (var item in await recentMovieRequests.ToListAsync(cancellationToken))
{
model.Add(new RecentlyRequestedModel
{
RequestId = item.Id,
Available = item.Available,
Overview = item.Overview,
ReleaseDate = item.ReleaseDate,
RequestDate = item.RequestedDate,
Title = item.Title,
Type = RequestType.Movie,
Approved = item.Approved,
UserId = item.RequestedUserId,
Username = item.RequestedUser.UserAlias
});
}
foreach (var item in await recentMusicRequests.ToListAsync(cancellationToken))
{
model.Add(new RecentlyRequestedModel
{
RequestId = item.Id,
Available = item.Available,
Overview = item.ArtistName,
Approved = item.Approved,
ReleaseDate = item.ReleaseDate,
RequestDate = item.RequestedDate,
Title = item.Title,
Type = RequestType.Album,
UserId = item.RequestedUserId,
Username = item.RequestedUser.UserAlias
});
}
foreach (var item in await recentTvRequests.ToListAsync(cancellationToken))
{
var partialAvailability = item.SeasonRequests.SelectMany(x => x.Episodes).Any(e => e.Available);
model.Add(new RecentlyRequestedModel
{
RequestId = item.Id,
Available = item.Available,
Overview = item.ParentRequest.Overview,
ReleaseDate = item.ParentRequest.ReleaseDate,
Approved = item.Approved,
RequestDate = item.RequestedDate,
TvPartiallyAvailable = partialAvailability,
Title = item.ParentRequest.Title,
Type = RequestType.TvShow,
UserId = item.RequestedUserId,
Username = item.RequestedUser.UserAlias
});
}
return model.OrderByDescending(x => x.RequestDate);
}
}
}

View file

@ -224,6 +224,7 @@ namespace Ombi.DependencyInjection
services.AddTransient<ITelegramNotification, TelegramNotification>(); services.AddTransient<ITelegramNotification, TelegramNotification>();
services.AddTransient<ILegacyMobileNotification, LegacyMobileNotification>(); services.AddTransient<ILegacyMobileNotification, LegacyMobileNotification>();
services.AddTransient<IChangeLogProcessor, ChangeLogProcessor>(); services.AddTransient<IChangeLogProcessor, ChangeLogProcessor>();
services.AddTransient<IRecentlyRequestedService, RecentlyRequestedService>();
} }
public static void RegisterJobs(this IServiceCollection services) public static void RegisterJobs(this IServiceCollection services)

View file

@ -12,6 +12,7 @@
public bool RecentlyAddedPage { get; set; } public bool RecentlyAddedPage { get; set; }
public bool UseCustomPage { get; set; } public bool UseCustomPage { get; set; }
public bool HideAvailableFromDiscover { get; set; } public bool HideAvailableFromDiscover { get; set; }
public bool HideAvailableRecentlyRequested { get; set; }
public string AddToUrl(string part) public string AddToUrl(string part)
{ {

View file

@ -13,6 +13,8 @@ using System.Linq;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Ombi.Attributes; using Ombi.Attributes;
using Ombi.Helpers; using Ombi.Helpers;
using Ombi.Core.Services;
using System.Collections.Generic;
namespace Ombi.Controllers.V2 namespace Ombi.Controllers.V2
{ {
@ -24,15 +26,17 @@ namespace Ombi.Controllers.V2
private readonly IMusicRequestEngine _musicRequestEngine; private readonly IMusicRequestEngine _musicRequestEngine;
private readonly IVoteEngine _voteEngine; private readonly IVoteEngine _voteEngine;
private readonly ILogger<RequestsController> _logger; private readonly ILogger<RequestsController> _logger;
private readonly IRecentlyRequestedService _recentlyRequestedService;
public RequestsController(IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine, IMusicRequestEngine musicRequestEngine, public RequestsController(IMovieRequestEngine movieRequestEngine, ITvRequestEngine tvRequestEngine, IMusicRequestEngine musicRequestEngine,
IVoteEngine voteEngine, ILogger<RequestsController> logger) IVoteEngine voteEngine, ILogger<RequestsController> logger, IRecentlyRequestedService recentlyRequestedService)
{ {
_movieRequestEngine = movieRequestEngine; _movieRequestEngine = movieRequestEngine;
_tvRequestEngine = tvRequestEngine; _tvRequestEngine = tvRequestEngine;
_musicRequestEngine = musicRequestEngine; _musicRequestEngine = musicRequestEngine;
_voteEngine = voteEngine; _voteEngine = voteEngine;
_logger = logger; _logger = logger;
_recentlyRequestedService = recentlyRequestedService;
} }
/// <summary> /// <summary>
@ -223,6 +227,12 @@ namespace Ombi.Controllers.V2
return await _movieRequestEngine.RequestCollection(collectionId, HttpContext.RequestAborted); return await _movieRequestEngine.RequestCollection(collectionId, HttpContext.RequestAborted);
} }
[HttpGet("recentlyRequested")]
public Task<IEnumerable<RecentlyRequestedModel>> RecentlyRequested()
{
return _recentlyRequestedService.GetRecentlyRequested(CancellationToken);
}
private string GetApiAlias() private string GetApiAlias()
{ {
// Make sure this only applies when using the API KEY // Make sure this only applies when using the API KEY