diff --git a/src/Ombi.Core.Tests/Engine/VoteEngineTests.cs b/src/Ombi.Core.Tests/Engine/VoteEngineTests.cs new file mode 100644 index 000000000..3cb439a55 --- /dev/null +++ b/src/Ombi.Core.Tests/Engine/VoteEngineTests.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Linq; +using System.Security.Principal; +using System.Threading.Tasks; +using Moq; +using NUnit.Framework; +using Ombi.Core.Authentication; +using Ombi.Core.Engine; +using Ombi.Core.Engine.Interfaces; +using Ombi.Core.Rule.Interfaces; +using Ombi.Core.Settings; +using Ombi.Settings.Settings.Models; +using Ombi.Store.Entities; +using Ombi.Store.Repository; + +namespace Ombi.Core.Tests.Engine +{ + [TestFixture] + public class VoteEngineTests + { + [SetUp] + public void Setup() + { + VoteRepository = new Mock>(); + VoteSettings = new Mock>(); + MusicRequestEngine = new Mock(); + TvRequestEngine = new Mock(); + MovieRequestEngine = new Mock(); + MovieRequestEngine = new Mock(); + User = new Mock(); + UserManager = new Mock(); + Rule = new Mock(); + Engine = new VoteEngine(VoteRepository.Object, User.Object, UserManager.Object, Rule.Object, VoteSettings.Object, MusicRequestEngine.Object, + TvRequestEngine.Object, MovieRequestEngine.Object); + } + + public VoteEngine Engine { get; set; } + public Mock User { get; set; } + public Mock UserManager { get; set; } + public Mock Rule { get; set; } + public Mock> VoteRepository { get; set; } + public Mock> VoteSettings { get; set; } + public Mock MusicRequestEngine { get; set; } + public Mock TvRequestEngine { get; set; } + public Mock MovieRequestEngine { get; set; } + + [Test] + public async Task New_Upvote() + { + var votes = new List(); + AutoFi + VoteRepository.Setup(x => x.GetAll()).Returns(new EnumerableQuery()) + var result = await Engine.UpVote(1, RequestType.Movie); + + } + } +} \ No newline at end of file diff --git a/src/Ombi.Core/Engine/VoteEngine.cs b/src/Ombi.Core/Engine/VoteEngine.cs index 5c132075e..3c9b0faad 100644 --- a/src/Ombi.Core/Engine/VoteEngine.cs +++ b/src/Ombi.Core/Engine/VoteEngine.cs @@ -6,91 +6,142 @@ using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Ombi.Core.Authentication; using Ombi.Core.Engine.Interfaces; +using Ombi.Core.Models; using Ombi.Core.Rule.Interfaces; +using Ombi.Core.Settings; +using Ombi.Settings.Settings.Models; using Ombi.Store.Entities; using Ombi.Store.Repository; -using Ombi.Store.Repository.Requests; namespace Ombi.Core.Engine { public class VoteEngine : BaseEngine { - public VoteEngine(IRepository votes, IPrincipal user, OmbiUserManager um, IRuleEvaluator r) : base(user, um, r) + public VoteEngine(IRepository votes, IPrincipal user, OmbiUserManager um, IRuleEvaluator r, ISettingsService voteSettings, + IMusicRequestEngine musicRequestEngine, ITvRequestEngine tvRequestEngine, IMovieRequestEngine movieRequestEngine) : base(user, um, r) { _voteRepository = votes; + _voteSettings = voteSettings; + _movieRequestEngine = movieRequestEngine; + _musicRequestEngine = musicRequestEngine; + _tvRequestEngine = tvRequestEngine; } private readonly IRepository _voteRepository; + private readonly ISettingsService _voteSettings; + private readonly IMusicRequestEngine _musicRequestEngine; + private readonly ITvRequestEngine _tvRequestEngine; + private readonly IMovieRequestEngine _movieRequestEngine; - public async Task GetVotesForMovie(int requestId) + public IQueryable GetVotes(int requestId, RequestType requestType) { - return await _voteRepository.GetAll().FirstOrDefaultAsync(x => x.RequestType == RequestType.Movie && x.RequestId == requestId); - } - public IQueryable GetVotesForMovie(IEnumerable requestIds) - { - return _voteRepository.GetAll().Where(x => x.RequestType == RequestType.Movie && requestIds.Contains(x.RequestId)); + return _voteRepository.GetAll().Where(x => x.RequestType == requestType && requestId == x.RequestId); } - public async Task GetVotesForTv(int requestId) + public Task GetVoteForUser(int requestId, string userId) { - return await _voteRepository.GetAll().FirstOrDefaultAsync(x => x.RequestType == RequestType.TvShow && x.RequestId == requestId); + return _voteRepository.GetAll().FirstOrDefaultAsync(x => x.RequestId == requestId && x.UserId == userId); } - public IQueryable GetVotesForTv(IEnumerable requestIds) + public async Task UpVote(int requestId, RequestType requestType) { - return _voteRepository.GetAll().Where(x => x.RequestType == RequestType.TvShow && requestIds.Contains(x.RequestId)); - } + // How many votes does this have?! + var currentVotes = GetVotes(requestId, requestType); + var voteSettings = await _voteSettings.GetSettingsAsync(); - public async Task UpvoteMovie(int requestId) - { + // Does this user have a downvote? If so we should revert it and make it an upvote var user = await GetUser(); + + var currentVote = await GetVoteForUser(requestId, user.Id); + if (currentVote != null && currentVote.VoteType == VoteType.Upvote) + { + return new VoteEngineResult { ErrorMessage = "You have already voted!" }; + } + await RemoveCurrentVote(currentVote); + await _voteRepository.Add(new Votes { Date = DateTime.UtcNow, RequestId = requestId, - RequestType = RequestType.Movie, + RequestType = requestType, UserId = user.Id, VoteType = VoteType.Upvote }); + + var upVotes = await currentVotes.Where(x => x.VoteType == VoteType.Upvote).CountAsync(); + var downVotes = -(await currentVotes.Where(x => x.VoteType == VoteType.Downvote).CountAsync()); + + var totalVotes = upVotes + downVotes; + RequestEngineResult result = null; + switch (requestType) + { + case RequestType.TvShow: + if (totalVotes >= voteSettings.TvShowVoteMax) + { + result = await _tvRequestEngine.ApproveChildRequest(requestId); + } + break; + case RequestType.Movie: + if (totalVotes >= voteSettings.MovieVoteMax) + { + result = await _movieRequestEngine.ApproveMovieById(requestId); + } + break; + case RequestType.Album: + if (totalVotes >= voteSettings.MusicVoteMax) + { + result = await _musicRequestEngine.ApproveAlbumById(requestId); + } + break; + default: + throw new ArgumentOutOfRangeException(nameof(requestType), requestType, null); + } + + if (result != null && !result.Result) + { + return new VoteEngineResult + { + ErrorMessage = "Voted succesfully but could not approve movie!" + }; + } + + return new VoteEngineResult + { + Result = true + }; } - public async Task DownvoteMovie(int requestId) + public async Task DownVote(int requestId, RequestType requestType) { var user = await GetUser(); + var currentVote = await GetVoteForUser(requestId, user.Id); + if (currentVote != null && currentVote.VoteType == VoteType.Upvote) + { + return new VoteEngineResult { ErrorMessage = "You have already voted!" }; + } + await RemoveCurrentVote(currentVote); + await _voteRepository.Add(new Votes { Date = DateTime.UtcNow, RequestId = requestId, - RequestType = RequestType.Movie, + RequestType = requestType, UserId = user.Id, VoteType = VoteType.Downvote }); - } - public async Task UpvoteTv(int requestId) - { - var user = await GetUser(); - await _voteRepository.Add(new Votes + return new VoteEngineResult { - Date = DateTime.UtcNow, - RequestId = requestId, - RequestType = RequestType.TvShow, - UserId = user.Id, - VoteType = VoteType.Upvote - }); + Result = true + }; } - public async Task DownvoteTv(int requestId) + public async Task RemoveCurrentVote(Votes currentVote) { - var user = await GetUser(); - await _voteRepository.Add(new Votes + if (currentVote != null) { - Date = DateTime.UtcNow, - RequestId = requestId, - RequestType = RequestType.TvShow, - UserId = user.Id, - VoteType = VoteType.Downvote - }); + await _voteRepository.Delete(currentVote); + } } } } \ No newline at end of file diff --git a/src/Ombi.Core/Models/VoteEngineResult.cs b/src/Ombi.Core/Models/VoteEngineResult.cs new file mode 100644 index 000000000..7546b0bb2 --- /dev/null +++ b/src/Ombi.Core/Models/VoteEngineResult.cs @@ -0,0 +1,10 @@ +namespace Ombi.Core.Models +{ + public class VoteEngineResult + { + public bool Result { get; set; } + public string Message { get; set; } + public bool IsError => !string.IsNullOrEmpty(ErrorMessage); + public string ErrorMessage { get; set; } + } +} \ No newline at end of file diff --git a/src/Ombi.Settings/Settings/Models/VoteSettings.cs b/src/Ombi.Settings/Settings/Models/VoteSettings.cs new file mode 100644 index 000000000..4d63cfea4 --- /dev/null +++ b/src/Ombi.Settings/Settings/Models/VoteSettings.cs @@ -0,0 +1,10 @@ +namespace Ombi.Settings.Settings.Models +{ + public class VoteSettings : Settings + { + public bool Enabled { get; set; } + public int MovieVoteMax { get; set; } + public int MusicVoteMax { get; set; } + public int TvShowVoteMax { get; set; } + } +} \ No newline at end of file