From 3b84fc33927646c652acfb8d6da80df5855aa1fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 14 Mar 2018 16:31:05 +0300 Subject: [PATCH] Created AuditPropertySetter and initial tests. Added TenantId to current user. --- Volo.Abp.sln | 7 ++ .../Volo.Abp.Auditing.csproj | 4 +- .../Volo.Abp.Auditing.csproj.DotSettings | 2 + .../Volo/Abp/Auditing/AbpAuditingModule.cs | 11 +- .../Volo/Abp/Auditing/AuditPropertySetter.cs | 111 ++++++++++++++++++ .../Volo/Abp/Auditing/IAuditPropertySetter.cs | 9 ++ .../Volo/Abp/Users/CurrentUser.cs | 17 +-- .../Volo/Abp/Users/ICurrentUser.cs | 4 +- .../Volo.Abp.Auditing.Tests.csproj | 24 ++++ ...Volo.Abp.Auditing.Tests.csproj.DotSettings | 2 + .../Auditing/AuditPropertySetterTestBase.cs | 57 +++++++++ ...AuditPropertySetter_CreationAudit_Tests.cs | 28 +++++ 12 files changed, 260 insertions(+), 16 deletions(-) create mode 100644 src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj.DotSettings create mode 100644 src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs create mode 100644 src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditPropertySetter.cs create mode 100644 test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj create mode 100644 test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj.DotSettings create mode 100644 test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetterTestBase.cs create mode 100644 test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetter_CreationAudit_Tests.cs diff --git a/Volo.Abp.sln b/Volo.Abp.sln index cf2f59c46e..82d3796336 100644 --- a/Volo.Abp.sln +++ b/Volo.Abp.sln @@ -308,6 +308,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Users", "src\Volo. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Auditing", "src\Volo.Abp.Auditing\Volo.Abp.Auditing.csproj", "{03F51721-DA51-4BAE-9909-3FC88FAB7774}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Auditing.Tests", "test\Volo.Abp.Auditing.Tests\Volo.Abp.Auditing.Tests.csproj", "{D5733D90-8C3D-4026-85E2-41DED26C4938}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -814,6 +816,10 @@ Global {03F51721-DA51-4BAE-9909-3FC88FAB7774}.Debug|Any CPU.Build.0 = Debug|Any CPU {03F51721-DA51-4BAE-9909-3FC88FAB7774}.Release|Any CPU.ActiveCfg = Release|Any CPU {03F51721-DA51-4BAE-9909-3FC88FAB7774}.Release|Any CPU.Build.0 = Release|Any CPU + {D5733D90-8C3D-4026-85E2-41DED26C4938}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5733D90-8C3D-4026-85E2-41DED26C4938}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5733D90-8C3D-4026-85E2-41DED26C4938}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5733D90-8C3D-4026-85E2-41DED26C4938}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -964,6 +970,7 @@ Global {F33F751F-1260-40C0-8F76-E3D680605662} = {447C8A77-E5F0-4538-8687-7383196D04EA} {DAE9088E-6E30-4D5D-9DF8-2188E8D386FE} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8} {03F51721-DA51-4BAE-9909-3FC88FAB7774} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8} + {D5733D90-8C3D-4026-85E2-41DED26C4938} = {37087D1B-3693-4E96-983D-A69F210BDE53} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj b/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj index 450efb7de6..04549d5441 100644 --- a/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj +++ b/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj @@ -14,8 +14,10 @@ - + + + diff --git a/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj.DotSettings b/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj.DotSettings new file mode 100644 index 0000000000..58ad6c8854 --- /dev/null +++ b/src/Volo.Abp.Auditing/Volo.Abp.Auditing.csproj.DotSettings @@ -0,0 +1,2 @@ + + CSharp71 \ No newline at end of file diff --git a/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs b/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs index 42532bfb3a..13202af3fe 100644 --- a/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs +++ b/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs @@ -1,10 +1,19 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Data; using Volo.Abp.Modularity; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; +using Volo.Abp.Users; namespace Volo.Abp.Auditing { - [DependsOn(typeof(AbpDataModule))] //TODO: Can we remove data module dependency since it only contains ISoftDelete related to auditing module! + //TODO: Can we remove AbpDataModule dependency since it only contains ISoftDelete related to auditing module! + [DependsOn( + typeof(AbpDataModule), + typeof(AbpTimingModule), + typeof(AbpUsersModule), + typeof(AbpMultiTenancyAbstractionsModule) + )] public class AbpAuditingModule : AbpModule { public override void ConfigureServices(IServiceCollection services) diff --git a/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs b/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs new file mode 100644 index 0000000000..715fcbc058 --- /dev/null +++ b/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditPropertySetter.cs @@ -0,0 +1,111 @@ +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; +using Volo.Abp.Users; + +namespace Volo.Abp.Auditing +{ + public class AuditPropertySetter : IAuditPropertySetter, ITransientDependency + { + protected ICurrentUser CurrentUser { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected IClock Clock { get; } + + public AuditPropertySetter( + ICurrentUser currentUser, + ICurrentTenant currentTenant, + IClock clock) + { + CurrentUser = currentUser; + CurrentTenant = currentTenant; + Clock = clock; + } + + public void SetCreationAuditProperties(object targetObject) + { + if (!(targetObject is IHasCreationTime objectWithCreationTime)) + { + return; + } + + if (objectWithCreationTime.CreationTime == default) + { + objectWithCreationTime.CreationTime = Clock.Now; + } + + if (!(targetObject is ICreationAudited creationAuditedObject)) + { + return; + } + + if (creationAuditedObject.CreatorId != null) + { + return; + } + + if (!CurrentUser.Id.HasValue) + { + return; + } + + if (targetObject is IMultiTenant multiTenantEntity) + { + if (multiTenantEntity.TenantId != CurrentUser.TenantId) + { + return; + } + } + + /* TODO: The code below is from old ABP, not implemented yet + if (tenantId.HasValue && MultiTenancyHelper.IsHostEntity(entity)) + { + //Tenant user created a host entity + return; + } + */ + + creationAuditedObject.CreatorId = CurrentUser.Id; + } + + public void SetModificationAuditProperties(object auditedObject) + { + if (auditedObject is IHasModificationTime objectWithModificationTime) + { + objectWithModificationTime.LastModificationTime = Clock.Now; + } + + if (!(auditedObject is IModificationAudited modificationAuditedObject)) + { + return; + } + + if (!CurrentUser.Id.HasValue) + { + modificationAuditedObject.LastModifierId = null; + return; + } + + if (modificationAuditedObject is IMultiTenant multiTenantEntity) + { + if (multiTenantEntity.TenantId != CurrentUser.TenantId) + { + modificationAuditedObject.LastModifierId = null; + return; + } + } + + /* TODO: The code below is from old ABP, not implemented yet + if (tenantId.HasValue && MultiTenancyHelper.IsHostEntity(entity)) + { + //Tenant user modified a host entity + modificationAuditedObject.LastModifierId = null; + return; + } + */ + + modificationAuditedObject.LastModifierId = CurrentUser.Id; + } + } +} diff --git a/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditPropertySetter.cs b/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditPropertySetter.cs new file mode 100644 index 0000000000..f8934fd895 --- /dev/null +++ b/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditPropertySetter.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.Auditing +{ + public interface IAuditPropertySetter + { + void SetCreationAuditProperties(object targetObject); + + void SetModificationAuditProperties(object auditedObject); + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Users/Volo/Abp/Users/CurrentUser.cs b/src/Volo.Abp.Users/Volo/Abp/Users/CurrentUser.cs index abcde115ab..884c9078f1 100644 --- a/src/Volo.Abp.Users/Volo/Abp/Users/CurrentUser.cs +++ b/src/Volo.Abp.Users/Volo/Abp/Users/CurrentUser.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Security.Claims; +using System.Security.Principal; using Volo.Abp.DependencyInjection; using Volo.Abp.Security.Claims; @@ -12,19 +13,7 @@ namespace Volo.Abp.Users public virtual bool IsAuthenticated => Id.HasValue; - public virtual Guid? Id - { - get - { - var value = this.FindClaimValue(AbpClaimTypes.UserId); - if (value == null) - { - return null; - } - - return Guid.Parse(value); - } - } + public virtual Guid? Id => _principalAccessor.Principal?.FindUserId(); public virtual string UserName => this.FindClaimValue(AbpClaimTypes.UserName); @@ -36,6 +25,8 @@ namespace Volo.Abp.Users public virtual bool EmailVerified => string.Equals(this.FindClaimValue(AbpClaimTypes.EmailVerified), "true", StringComparison.InvariantCultureIgnoreCase); + public virtual Guid? TenantId => _principalAccessor.Principal?.FindTenantId(); + public virtual string[] Roles => FindClaims(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); private readonly ICurrentPrincipalAccessor _principalAccessor; diff --git a/src/Volo.Abp.Users/Volo/Abp/Users/ICurrentUser.cs b/src/Volo.Abp.Users/Volo/Abp/Users/ICurrentUser.cs index 46bcb7d308..d2aebf8e93 100644 --- a/src/Volo.Abp.Users/Volo/Abp/Users/ICurrentUser.cs +++ b/src/Volo.Abp.Users/Volo/Abp/Users/ICurrentUser.cs @@ -16,7 +16,7 @@ namespace Volo.Abp.Users [CanBeNull] string PhoneNumber { get; } - + bool PhoneNumberVerified { get; } [CanBeNull] @@ -24,6 +24,8 @@ namespace Volo.Abp.Users bool EmailVerified { get; } + Guid? TenantId { get; } + [NotNull] string[] Roles { get; } diff --git a/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj b/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj new file mode 100644 index 0000000000..ac881ee3af --- /dev/null +++ b/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp2.0 + latest + Volo.Abp.Auditing.Tests + Volo.Abp.Auditing.Tests + true + false + false + false + + + + + + + + + + + + + diff --git a/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj.DotSettings b/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj.DotSettings new file mode 100644 index 0000000000..58ad6c8854 --- /dev/null +++ b/test/Volo.Abp.Auditing.Tests/Volo.Abp.Auditing.Tests.csproj.DotSettings @@ -0,0 +1,2 @@ + + CSharp71 \ No newline at end of file diff --git a/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetterTestBase.cs b/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetterTestBase.cs new file mode 100644 index 0000000000..4bdad632be --- /dev/null +++ b/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetterTestBase.cs @@ -0,0 +1,57 @@ +using System; +using NSubstitute; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; +using Volo.Abp.Users; + +namespace Volo.Abp.Auditing +{ + public class AuditPropertySetterTestBase + { + protected Guid? CurrentUserId = null; + protected Guid? CurrentUserTenantId = null; + protected Guid? CurrentTenantId = null; + + protected DateTime Now = DateTime.Now; + + protected MyAuditedObject TargetObject; + + protected readonly AuditPropertySetter AuditPropertySetter; + + public AuditPropertySetterTestBase() + { + AuditPropertySetter = CreateAuditPropertySetter(); + TargetObject = new MyAuditedObject(); + } + + private AuditPropertySetter CreateAuditPropertySetter() + { + var currentUser = Substitute.For(); + currentUser.Id.Returns(ci => CurrentUserId); + currentUser.TenantId.Returns(ci => CurrentUserTenantId); + + var currentTenant = Substitute.For(); + currentTenant.Id.Returns(ci => CurrentTenantId); + + var clock = Substitute.For(); + clock.Now.Returns(Now); + + return new AuditPropertySetter( + currentUser, + currentTenant, + clock + ); + } + + public class MyAuditedObject : IFullAudited + { + public DateTime CreationTime { get; set; } + public Guid? CreatorId { get; set; } + public DateTime? LastModificationTime { get; set; } + public Guid? LastModifierId { get; set; } + public bool IsDeleted { get; set; } + public DateTime? DeletionTime { get; set; } + public Guid? DeleterId { get; set; } + } + } +} diff --git a/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetter_CreationAudit_Tests.cs b/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetter_CreationAudit_Tests.cs new file mode 100644 index 0000000000..5ea1b120e5 --- /dev/null +++ b/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AuditPropertySetter_CreationAudit_Tests.cs @@ -0,0 +1,28 @@ +using System; +using Shouldly; +using Xunit; + +namespace Volo.Abp.Auditing +{ + public class AuditPropertySetter_CreationAudit_Tests : AuditPropertySetterTestBase + { + [Fact] + public void Should_Set_CreationTime() + { + AuditPropertySetter.SetCreationAuditProperties(TargetObject); + + TargetObject.CreationTime.ShouldNotBe(default); + } + + [Fact] + public void Should_Set_CreatorId() + { + CurrentUserId = Guid.NewGuid(); + + AuditPropertySetter.SetCreationAuditProperties(TargetObject); + + TargetObject.CreationTime.ShouldNotBe(default); + TargetObject.CreatorId.ShouldBe(CurrentUserId); + } + } +} \ No newline at end of file