Added the Rules Engine Pattern and the Auto approve and request rules #865

pull/1425/head
tidusjar 7 years ago
parent 7f2cfdafd1
commit d10b0f7081

@ -14,6 +14,7 @@ before_build:
- gulp publish
build_script:
- dotnet build
- dotnet xunit
after_build:
- dotnet publish -c Release -r win10-x64
- dotnet publish -c Release -r osx.10.12-x64

@ -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>

@ -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);
}
}
}

@ -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);
}
}

@ -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"));
}
}
}

@ -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…
Cancel
Save