Browse Source

Resolved #890: Handle audit log if there are tenant switches in the same request.

pull/947/head
Halil ibrahim Kalkan 8 years ago
parent
commit
1d79b95a38
  1. 1
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs
  2. 5
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs
  3. 3
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs
  4. 14
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs
  5. 10
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs
  6. 12
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs
  7. 5
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs
  8. 14
      framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs
  9. 5
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  10. 32
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLog.cs
  11. 4
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogAction.cs
  12. 23
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityChange.cs
  13. 8
      modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityPropertyChange.cs
  14. 1
      modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditStore_Basic_Tests.cs
  15. 76
      modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs

1
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Auditing/AbpAuditActionFilter.cs

@ -92,6 +92,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Auditing
auditLog = auditLogScope.Log;
auditLogAction = _auditingHelper.CreateAuditLogAction(
auditLog,
context.ActionDescriptor.AsControllerActionDescriptor().ControllerTypeInfo.AsType(),
context.ActionDescriptor.AsControllerActionDescriptor().MethodInfo,
context.ActionArguments

5
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogActionInfo.cs

@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
[Serializable]
public class AuditLogActionInfo : IMultiTenant, IHasExtraProperties
public class AuditLogActionInfo : IHasExtraProperties
{
public Guid? TenantId { get; set; }
public string ServiceName { get; set; }
public string MethodName { get; set; }

3
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditLogInfo.cs

@ -3,12 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
[Serializable]
public class AuditLogInfo : IMultiTenant, IHasExtraProperties
public class AuditLogInfo : IHasExtraProperties
{
public string ApplicationName { get; set; }

14
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingHelper.cs

@ -107,12 +107,20 @@ namespace Volo.Abp.Auditing
return auditInfo;
}
public virtual AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, object[] arguments)
public virtual AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
object[] arguments)
{
return CreateAuditLogAction(type, method, CreateArgumentsDictionary(method, arguments));
return CreateAuditLogAction(auditLog, type, method, CreateArgumentsDictionary(method, arguments));
}
public virtual AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, IDictionary<string, object> arguments)
public virtual AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
IDictionary<string, object> arguments)
{
var actionInfo = new AuditLogActionInfo
{

10
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AuditingInterceptor.cs

@ -72,7 +72,10 @@ namespace Volo.Abp.Auditing
}
}
protected virtual bool ShouldIntercept(IAbpMethodInvocation invocation, out AuditLogInfo auditLog, out AuditLogActionInfo auditLogAction)
protected virtual bool ShouldIntercept(
IAbpMethodInvocation invocation,
out AuditLogInfo auditLog,
out AuditLogActionInfo auditLogAction)
{
auditLog = null;
auditLogAction = null;
@ -95,7 +98,10 @@ namespace Volo.Abp.Auditing
auditLog = auditLogScope.Log;
auditLogAction = _auditingHelper.CreateAuditLogAction(
invocation.TargetObject.GetType(), invocation.Method, invocation.Arguments
auditLog,
invocation.TargetObject.GetType(),
invocation.Method,
invocation.Arguments
);
return true;

12
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityChangeInfo.cs

@ -2,23 +2,27 @@
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
[Serializable]
public class EntityChangeInfo : IMultiTenant, IHasExtraProperties
public class EntityChangeInfo : IHasExtraProperties
{
public DateTime ChangeTime { get; set; }
public EntityChangeType ChangeType { get; set; }
/// <summary>
/// TenantId of the related entity.
/// This is not the TenantId of the audit log entry.
/// There can be multiple tenant data changes in a single audit log entry.
/// </summary>
public Guid? EntityTenantId { get; set; }
public string EntityId { get; set; }
public string EntityTypeFullName { get; set; }
public Guid? TenantId { get; set; }
public List<EntityPropertyChangeInfo> PropertyChanges { get; set; }
public Dictionary<string, object> ExtraProperties { get; }

5
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/EntityPropertyChangeInfo.cs

@ -1,10 +1,9 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Auditing
{
[Serializable]
public class EntityPropertyChangeInfo : IMultiTenant
public class EntityPropertyChangeInfo
{
/// <summary>
/// Maximum length of <see cref="PropertyName"/> property.
@ -24,8 +23,6 @@ namespace Volo.Abp.Auditing
/// </summary>
public const int MaxPropertyTypeFullNameLength = 192;
public Guid? TenantId { get; set; }
public virtual string NewValue { get; set; }
public virtual string OriginalValue { get; set; }

14
framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/IAuditingHelper.cs

@ -11,8 +11,18 @@ namespace Volo.Abp.Auditing
AuditLogInfo CreateAuditLogInfo();
AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, object[] arguments);
AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
object[] arguments
);
AuditLogActionInfo CreateAuditLogAction(Type type, MethodInfo method, IDictionary<string, object> arguments);
AuditLogActionInfo CreateAuditLogAction(
AuditLogInfo auditLog,
Type type,
MethodInfo method,
IDictionary<string, object> arguments
);
}
}

5
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

@ -103,7 +103,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
EntityId = entityId,
EntityTypeFullName = entityType.FullName,
PropertyChanges = GetPropertyChanges(entityEntry),
TenantId = GetTenantId(entity)
EntityTenantId = GetTenantId(entity)
};
return entityChange;
@ -171,8 +171,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
NewValue = isDeleted ? null : JsonSerializer.Serialize(propertyEntry.CurrentValue).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength),
OriginalValue = isCreated ? null : JsonSerializer.Serialize(propertyEntry.OriginalValue).TruncateWithPostfix(EntityPropertyChangeInfo.MaxValueLength),
PropertyName = property.Name,
PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName,
TenantId = GetTenantId(entityEntry.Entity)
PropertyTypeFullName = property.ClrType.GetFirstGenericArgumentIfNullable().FullName
});
}
}

32
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLog.cs

@ -78,11 +78,33 @@ namespace Volo.Abp.AuditLogging
HttpStatusCode = auditInfo.HttpStatusCode;
ImpersonatorUserId = auditInfo.ImpersonatorUserId;
ImpersonatorTenantId = auditInfo.ImpersonatorTenantId;
ExtraProperties = auditInfo.ExtraProperties.ToDictionary(pair => pair.Key, pair => pair.Value);
EntityChanges = auditInfo.EntityChanges.Select(e => new EntityChange(guidGenerator, Id, e)).ToList();
Actions = auditInfo.Actions.Select(e => new AuditLogAction(guidGenerator.Create(), Id, e)).ToList();
Exceptions = auditInfo.Exceptions.JoinAsString(Environment.NewLine).Truncate(AuditLogConsts.MaxExceptionsLength);
Comments = auditInfo.Comments.JoinAsString(Environment.NewLine).Truncate(AuditLogConsts.MaxCommentsLength);
ExtraProperties = auditInfo
.ExtraProperties?
.ToDictionary(pair => pair.Key, pair => pair.Value)
?? new Dictionary<string, object>();
EntityChanges = auditInfo
.EntityChanges?
.Select(entityChangeInfo => new EntityChange(guidGenerator, Id, entityChangeInfo, tenantId: auditInfo.TenantId))
.ToList()
?? new List<EntityChange>();
Actions = auditInfo
.Actions?
.Select(auditLogActionInfo => new AuditLogAction(guidGenerator.Create(), Id, auditLogActionInfo, tenantId: auditInfo.TenantId))
.ToList()
?? new List<AuditLogAction>();
Exceptions = auditInfo
.Exceptions?
.JoinAsString(Environment.NewLine)
.Truncate(AuditLogConsts.MaxExceptionsLength);
Comments = auditInfo
.Comments?
.JoinAsString(Environment.NewLine)
.Truncate(AuditLogConsts.MaxCommentsLength);
}
}
}

4
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/AuditLogAction.cs

@ -32,11 +32,11 @@ namespace Volo.Abp.AuditLogging
ExtraProperties = new Dictionary<string, object>();
}
public AuditLogAction(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo)
public AuditLogAction(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo, Guid? tenantId = null)
{
Id = id;
TenantId = actionInfo.TenantId;
TenantId = tenantId;
AuditLogId = auditLogId;
ExecutionTime = actionInfo.ExecutionTime;
ExecutionDuration = actionInfo.ExecutionDuration;

23
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityChange.cs

@ -20,6 +20,8 @@ namespace Volo.Abp.AuditLogging
public virtual EntityChangeType ChangeType { get; protected set; }
public virtual Guid? EntityTenantId { get; protected set; }
public virtual string EntityId { get; protected set; }
public virtual string EntityTypeFullName { get; protected set; }
@ -33,17 +35,30 @@ namespace Volo.Abp.AuditLogging
ExtraProperties = new Dictionary<string, object>();
}
public EntityChange(IGuidGenerator guidGenerator, Guid auditLogId, EntityChangeInfo entityChangeInfo)
public EntityChange(
IGuidGenerator guidGenerator,
Guid auditLogId,
EntityChangeInfo entityChangeInfo,
Guid? tenantId = null)
{
Id = guidGenerator.Create();
AuditLogId = auditLogId;
TenantId = entityChangeInfo.TenantId;
TenantId = tenantId;
ChangeTime = entityChangeInfo.ChangeTime;
ChangeType = entityChangeInfo.ChangeType;
EntityId = entityChangeInfo.EntityId.Truncate(EntityChangeConsts.MaxEntityTypeFullNameLength);
EntityTypeFullName = entityChangeInfo.EntityTypeFullName.TruncateFromBeginning(EntityChangeConsts.MaxEntityTypeFullNameLength);
PropertyChanges = entityChangeInfo.PropertyChanges.Select(p => new EntityPropertyChange(guidGenerator, Id, p)).ToList();
ExtraProperties = entityChangeInfo.ExtraProperties.ToDictionary(pair => pair.Key, pair => pair.Value);
PropertyChanges = entityChangeInfo
.PropertyChanges?
.Select(p => new EntityPropertyChange(guidGenerator, Id, p, tenantId))
.ToList()
?? new List<EntityPropertyChange>();
ExtraProperties = entityChangeInfo
.ExtraProperties?
.ToDictionary(pair => pair.Key, pair => pair.Value)
?? new Dictionary<string, object>();
}
}
}

8
modules/audit-logging/src/Volo.Abp.AuditLogging.Domain/Volo/Abp/AuditLogging/EntityPropertyChange.cs

@ -26,10 +26,14 @@ namespace Volo.Abp.AuditLogging
}
public EntityPropertyChange(IGuidGenerator guidGenerator, Guid entityChangeId, EntityPropertyChangeInfo entityChangeInfo)
public EntityPropertyChange(
IGuidGenerator guidGenerator,
Guid entityChangeId,
EntityPropertyChangeInfo entityChangeInfo,
Guid? tenantId = null)
{
Id = guidGenerator.Create();
TenantId = entityChangeInfo.TenantId;
TenantId = tenantId;
EntityChangeId = entityChangeId;
NewValue = entityChangeInfo.NewValue.Truncate(EntityPropertyChangeConsts.MaxNewValueLength);
OriginalValue = entityChangeInfo.OriginalValue.Truncate(EntityPropertyChangeConsts.MaxOriginalValueLength);

1
modules/audit-logging/test/Volo.Abp.AuditLogging.TestBase/Volo/Abp/AuditLogging/AuditStore_Basic_Tests.cs

@ -78,7 +78,6 @@ namespace Volo.Abp.AuditLogging
insertedLog.EntityChanges.First().PropertyChanges.Count.ShouldBeGreaterThan(0);
}
[Fact]
public async Task Should_Get_List_Of_Audit_Logs()
{

76
modules/audit-logging/test/Volo.Abp.AuditLogging.Tests/Volo/Abp/AuditLogging/MultiTenantAuditLog_Tests.cs

@ -0,0 +1,76 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Auditing;
using Xunit;
namespace Volo.Abp.AuditLogging
{
public class MultiTenantAuditLog_Tests : AuditLogsTestBase
{
private readonly IAuditingManager _auditingManager;
private readonly IAuditLogRepository _auditLogRepository;
public MultiTenantAuditLog_Tests()
{
_auditingManager = GetRequiredService<IAuditingManager>();
_auditLogRepository = GetRequiredService<IAuditLogRepository>();
}
[Fact]
public async Task Should_Save_Audit_Logs_To_The_Tenant_Begins_The_Scope()
{
//Arrange
var applicationName = Guid.NewGuid().ToString();
var tenantId = Guid.NewGuid();
var entityId1 = Guid.NewGuid();
var entityId2 = Guid.NewGuid();
//Act
using (var scope = _auditingManager.BeginScope())
{
_auditingManager.Current.Log.ApplicationName = applicationName;
//Creating a host entity
_auditingManager.Current.Log.EntityChanges.Add(
new EntityChangeInfo
{
ChangeTime = DateTime.Now,
ChangeType = EntityChangeType.Created,
EntityEntry = new object(),
EntityId = entityId1.ToString(),
EntityTypeFullName = "TestEntity"
}
);
//Creating a tenant entity
_auditingManager.Current.Log.EntityChanges.Add(
new EntityChangeInfo
{
ChangeTime = DateTime.Now,
ChangeType = EntityChangeType.Created,
EntityEntry = new object(),
EntityId = entityId2.ToString(),
EntityTypeFullName = "TestEntity",
EntityTenantId = tenantId
}
);
await scope.SaveAsync();
}
//Assert
var auditLogs = await _auditLogRepository.GetListAsync(applicationName: applicationName, includeDetails: true);
auditLogs.Count.ShouldBe(1);
var auditLog = auditLogs.First();
auditLog.EntityChanges.ShouldNotBeNull();
auditLog.EntityChanges.Count.ShouldBe(2);
auditLog.EntityChanges.ShouldContain(e => e.EntityId == entityId1.ToString());
auditLog.EntityChanges.ShouldContain(e => e.EntityId == entityId2.ToString());
}
}
}
Loading…
Cancel
Save