mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-14 02:26:55 -07:00
Added the Rules Engine Pattern and the Auto approve and request rules #865
This commit is contained in:
parent
7f2cfdafd1
commit
d10b0f7081
11 changed files with 238 additions and 48 deletions
|
@ -5,16 +5,14 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.7.8" />
|
||||
<PackageReference Include="Moq" Version="4.7.10" />
|
||||
<PackageReference Include="xunit" Version="2.2.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ombi.Core\Ombi.Core.csproj" />
|
||||
<ProjectReference Include="..\Ombi.Store\Ombi.Store.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
87
src/Ombi.Core.Tests/Rule/AutoApproveRuleTests.cs
Normal file
87
src/Ombi.Core.Tests/Rule/AutoApproveRuleTests.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using Ombi.Core.Rule.Rules;
|
||||
using Xunit;
|
||||
using System.Security.Principal;
|
||||
using Moq;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Claims;
|
||||
|
||||
namespace Ombi.Core.Tests
|
||||
{
|
||||
public class AutoApproveRuleTests
|
||||
{
|
||||
public AutoApproveRuleTests()
|
||||
{
|
||||
PrincipalMock = new Mock<IPrincipal>();
|
||||
Rule = new AutoApproveRule(PrincipalMock.Object);
|
||||
}
|
||||
|
||||
private AutoApproveRule Rule { get; }
|
||||
private Mock<IPrincipal> PrincipalMock { get; }
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenAdminAndRequestMovie()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenAdminAndRequestTV()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenAutoApproveMovieAndRequestMovie()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.AutoApproveMovie)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenAutoApproveTVAndRequestTV()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.AutoApproveTv)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnFail_WhenNoClaimsAndRequestMovie()
|
||||
{
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnFail_WhenNoClaimsAndRequestTV()
|
||||
{
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
Assert.Equal(request.Approved, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
83
src/Ombi.Core.Tests/Rule/CanRequestRuleTests.cs
Normal file
83
src/Ombi.Core.Tests/Rule/CanRequestRuleTests.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
using Ombi.Core.Rule.Rules;
|
||||
using Xunit;
|
||||
using System.Security.Principal;
|
||||
using Moq;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Claims;
|
||||
|
||||
namespace Ombi.Core.Tests
|
||||
{
|
||||
public class CanRequestRuleTests
|
||||
{
|
||||
public CanRequestRuleTests()
|
||||
{
|
||||
PrincipalMock = new Mock<IPrincipal>();
|
||||
Rule = new CanRequestRule(PrincipalMock.Object);
|
||||
}
|
||||
|
||||
private CanRequestRule Rule { get; }
|
||||
private Mock<IPrincipal> PrincipalMock { get; }
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenRequestingMovieWithMovieRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestMovie)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnFail_WhenRequestingMovieWithoutMovieRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestMovie)).Returns(false);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, false);
|
||||
Assert.Equal(string.IsNullOrEmpty(result.Message), false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenRequestingMovieWithAdminRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.Movie };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenRequestingTVWithAdminRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.Admin)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnSuccess_WhenRequestingTVWithTVRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestTv)).Returns(true);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Should_ReturnFail_WhenRequestingTVWithoutTVRole()
|
||||
{
|
||||
PrincipalMock.Setup(x => x.IsInRole(OmbiClaims.RequestTv)).Returns(false);
|
||||
var request = new BaseRequestModel() { Type = Store.Entities.RequestType.TvShow };
|
||||
var result = Rule.Execute(request);
|
||||
|
||||
Assert.Equal(result.Success, false);
|
||||
Assert.Equal(string.IsNullOrEmpty(result.Message), false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using Ombi.Core.Rule;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ombi.Core.Rules
|
||||
|
@ -19,8 +20,17 @@ namespace Ombi.Core.Rules
|
|||
{
|
||||
if (ti?.BaseType?.FullName == baseType)
|
||||
{
|
||||
var type = ti.GetType();
|
||||
var item = Activator.CreateInstance(ti.GetType(), provider.GetService(type));// ti.GetType is wrong
|
||||
var type = ti.AsType();
|
||||
var ctors = type.GetConstructors();
|
||||
var ctor = ctors.FirstOrDefault();
|
||||
|
||||
var services = new List<object>();
|
||||
foreach (var param in ctor.GetParameters())
|
||||
{
|
||||
services.Add(provider.GetService(param.ParameterType));
|
||||
}
|
||||
|
||||
var item = Activator.CreateInstance(type, services.ToArray());// ti.GetType is wrong
|
||||
RequestRules.Add((IRequestRules<BaseRequestModel>)item);
|
||||
}
|
||||
}
|
||||
|
|
38
src/Ombi.Core/Rule/Rules/AutoApproveRule.cs
Normal file
38
src/Ombi.Core/Rule/Rules/AutoApproveRule.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
using Ombi.Core.Claims;
|
||||
using Ombi.Core.Models.Requests;
|
||||
using Ombi.Core.Rules;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
|
||||
namespace Ombi.Core.Rule.Rules
|
||||
{
|
||||
public class AutoApproveRule : BaseRule, IRequestRules<BaseRequestModel>
|
||||
{
|
||||
public AutoApproveRule(IPrincipal principal)
|
||||
{
|
||||
User = principal;
|
||||
}
|
||||
|
||||
private IPrincipal User { get; }
|
||||
public RuleResult Execute(BaseRequestModel obj)
|
||||
{
|
||||
if(User.IsInRole(OmbiClaims.Admin))
|
||||
{
|
||||
obj.Approved = true;
|
||||
return Success();
|
||||
}
|
||||
|
||||
if (obj.Type == Store.Entities.RequestType.Movie && User.IsInRole(OmbiClaims.AutoApproveMovie))
|
||||
{
|
||||
obj.Approved = true;
|
||||
}
|
||||
if (obj.Type == Store.Entities.RequestType.TvShow && User.IsInRole(OmbiClaims.AutoApproveTv))
|
||||
{
|
||||
obj.Approved = true;
|
||||
}
|
||||
return Success(); // We don't really care, we just don't set the obj to approve
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ using System.Security.Principal;
|
|||
|
||||
namespace Ombi.Core.Rule.Rules
|
||||
{
|
||||
public class CanRequestRule<T> : BaseRule where T : BaseRequestModel, IRequestRules<T>
|
||||
public class CanRequestRule : BaseRule, IRequestRules<BaseRequestModel>
|
||||
{
|
||||
public CanRequestRule(IPrincipal principal)
|
||||
{
|
||||
|
@ -13,8 +13,13 @@ namespace Ombi.Core.Rule.Rules
|
|||
}
|
||||
|
||||
private IPrincipal User { get; }
|
||||
public RuleResult Execute(T obj)
|
||||
public RuleResult Execute(BaseRequestModel obj)
|
||||
{
|
||||
if(User.IsInRole(OmbiClaims.Admin))
|
||||
{
|
||||
return Success();
|
||||
}
|
||||
|
||||
if (obj.Type == Store.Entities.RequestType.Movie)
|
||||
{
|
||||
if (User.IsInRole(OmbiClaims.RequestMovie))
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace Ombi.DependencyInjection
|
|||
services.AddTransient<IMovieRequestEngine, MovieRequestEngine>();
|
||||
services.AddTransient<ITvRequestEngine, TvRequestEngine>();
|
||||
services.AddTransient<ITvSearchEngine, TvSearchEngine>();
|
||||
services.AddTransient<IRuleEvaluator, RuleEvaluator>();
|
||||
services.AddSingleton<IRuleEvaluator, RuleEvaluator>();
|
||||
}
|
||||
|
||||
public static void RegisterApi(this IServiceCollection services)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MailKit" Version="1.16.0" />
|
||||
<PackageReference Include="MailKit" Version="1.16.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Moq;
|
||||
using Ombi.Core.IdentityResolver;
|
||||
using Ombi.Core.Models;
|
||||
using Ombi.Store.Entities;
|
||||
using Ombi.Store.Repository;
|
||||
using Xunit;
|
||||
|
||||
namespace Ombi.Tests.Core
|
||||
{
|
||||
public class UserIdentityManagerTests
|
||||
{
|
||||
public UserIdentityManagerTests()
|
||||
{
|
||||
UserRepo = new Mock<IUserRepository>();
|
||||
var mapper = new Mock<IMapper>();
|
||||
Manager = new UserIdentityManager(UserRepo.Object, mapper.Object);
|
||||
}
|
||||
private Mock<IUserRepository> UserRepo { get; }
|
||||
private IUserIdentityManager Manager { get; }
|
||||
|
||||
[Fact]
|
||||
public async Task CredentialsValid()
|
||||
{
|
||||
UserRepo.Setup(x => x.GetUser("ABC")).ReturnsAsync(() => new User{Password = "4tDKIbNCZ0pMxNzSSjVbT6mG88o52x9jOixPEwQS9rg=", Salt = new byte[]{30,80,214,127,185,134,75,86,80,177,0,242,202,161,219,246}});
|
||||
|
||||
Assert.True(await Manager.CredentialsValid("ABC", "ABC"));
|
||||
}
|
||||
}
|
||||
}
|
14
src/Ombi.sln
14
src/Ombi.sln
|
@ -53,12 +53,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications.Email",
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Notifications.Templates", "Ombi.Notifications.Templates\Ombi.Notifications.Templates.csproj", "{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Tests.Core", "Ombi.Tests.Core\Ombi.Tests.Core.csproj", "{627A27A7-8879-4851-8140-38F8F5ADD6CD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Settings", "Ombi.Settings\Ombi.Settings.csproj", "{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Api.Trakt", "Ombi.Api.Trakt\Ombi.Api.Trakt.csproj", "{3880375C-1A7E-4D75-96EC-63B954C42FEA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ombi.Core.Tests", "Ombi.Core.Tests\Ombi.Core.Tests.csproj", "{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -129,10 +129,6 @@ Global
|
|||
{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6EE01B17-0966-4E11-8BC1-A5318A92AB1D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{627A27A7-8879-4851-8140-38F8F5ADD6CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{627A27A7-8879-4851-8140-38F8F5ADD6CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{627A27A7-8879-4851-8140-38F8F5ADD6CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{627A27A7-8879-4851-8140-38F8F5ADD6CD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AE3AA23D-5B66-42AF-B44E-B9B4D8856C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -141,6 +137,10 @@ Global
|
|||
{3880375C-1A7E-4D75-96EC-63B954C42FEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3880375C-1A7E-4D75-96EC-63B954C42FEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3880375C-1A7E-4D75-96EC-63B954C42FEA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -157,7 +157,7 @@ Global
|
|||
{E6EE2830-E4AC-4F2E-AD93-2C9305605761} = {EA30DD15-6280-4687-B370-2956EC2E54E5}
|
||||
{72DB97D7-2D60-4B96-8C57-6C0E20E892EB} = {EA30DD15-6280-4687-B370-2956EC2E54E5}
|
||||
{6EE01B17-0966-4E11-8BC1-A5318A92AB1D} = {EA30DD15-6280-4687-B370-2956EC2E54E5}
|
||||
{627A27A7-8879-4851-8140-38F8F5ADD6CD} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
|
||||
{3880375C-1A7E-4D75-96EC-63B954C42FEA} = {9293CA11-360A-4C20-A674-B9E794431BF5}
|
||||
{FC6A8F7C-9722-4AE4-960D-277ACB0E81CB} = {6F42AB98-9196-44C4-B888-D5E409F415A1}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue