mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-22 22:23:34 -07:00
feat(discover): ✨ Added a new API to query recently requested content
This commit is contained in:
parent
acc66fad49
commit
7d3be883d6
7 changed files with 326 additions and 1 deletions
170
src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs
Normal file
170
src/Ombi.Core.Tests/Services/RecentlyRequestedServiceTests.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs
Normal file
20
src/Ombi.Core/Models/Requests/RecentlyRequestedModel.cs
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
12
src/Ombi.Core/Services/IRecentlyRequestedService.cs
Normal file
12
src/Ombi.Core/Services/IRecentlyRequestedService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
111
src/Ombi.Core/Services/RecentlyRequestedService.cs
Normal file
111
src/Ombi.Core/Services/RecentlyRequestedService.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue