Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Volo.Abp.Auditing;

public class AuditingDisabledState
{
public bool IsDisabled { get; private set; }

public AuditingDisabledState(bool isDisabled)
{
IsDisabled = isDisabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Volo.Abp.Clients;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.Timing;
using Volo.Abp.Tracing;
using Volo.Abp.Users;
Expand All @@ -26,6 +27,7 @@ public class AuditingHelper : IAuditingHelper, ITransientDependency
protected IAuditSerializer AuditSerializer;
protected IServiceProvider ServiceProvider;
protected ICorrelationIdProvider CorrelationIdProvider { get; }
protected IAmbientScopeProvider<AuditingDisabledState> AuditingDisabledState { get; }

public AuditingHelper(
IAuditSerializer auditSerializer,
Expand All @@ -37,7 +39,8 @@ public AuditingHelper(
IAuditingStore auditingStore,
ILogger<AuditingHelper> logger,
IServiceProvider serviceProvider,
ICorrelationIdProvider correlationIdProvider)
ICorrelationIdProvider correlationIdProvider,
IAmbientScopeProvider<AuditingDisabledState> auditingDisabledState)
{
Options = options.Value;
AuditSerializer = auditSerializer;
Expand All @@ -50,6 +53,7 @@ public AuditingHelper(
Logger = logger;
ServiceProvider = serviceProvider;
CorrelationIdProvider = correlationIdProvider;
AuditingDisabledState = auditingDisabledState;
}

public virtual bool ShouldSaveAudit(MethodInfo? methodInfo, bool defaultValue = false, bool ignoreIntegrationServiceAttribute = false)
Expand All @@ -64,6 +68,11 @@ public virtual bool ShouldSaveAudit(MethodInfo? methodInfo, bool defaultValue =
return false;
}

if (!IsAuditingEnabled())
{
return false;
}

if (methodInfo.IsDefined(typeof(AuditedAttribute), true))
{
return true;
Expand Down Expand Up @@ -178,6 +187,19 @@ public virtual AuditLogActionInfo CreateAuditLogAction(
return actionInfo;
}

private const string AuditingDisabledScopeKey = "Volo.Abp.Auditing.DisabledScope";

public virtual IDisposable DisableAuditing()
{
return AuditingDisabledState.BeginScope(AuditingDisabledScopeKey, new AuditingDisabledState(true));
}

public virtual bool IsAuditingEnabled()
{
var state = AuditingDisabledState.GetValue(AuditingDisabledScopeKey);
return state == null || !state.IsDisabled;
}

protected virtual void ExecutePreContributors(AuditLogInfo auditLogInfo)
{
using (var scope = ServiceProvider.CreateScope())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,23 @@ AuditLogActionInfo CreateAuditLogAction(
MethodInfo method,
IDictionary<string, object?> arguments
);

/// <summary>
/// Creates a scope in which auditing is temporarily disabled.
/// </summary>
/// <returns>
/// An <see cref="IDisposable"/> that restores the previous auditing state
/// when disposed. This method supports nested scopes; disposing a scope
/// restores the auditing state that was active before that scope was created.
/// </returns>
IDisposable DisableAuditing();

/// <summary>
/// Determines whether auditing is currently enabled.
/// </summary>
/// <returns>
/// <c>true</c> if auditing is enabled in the current context; otherwise, <c>false</c>.
/// This reflects any active scopes created by <see cref="DisableAuditing"/>.
/// </returns>
bool IsAuditingEnabled();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NSubstitute;
using Volo.Abp.DependencyInjection;
using Xunit;

namespace Volo.Abp.Auditing;

public class AuditingHelper_Tests : AbpAuditingTestBase
{
private readonly IAuditingHelper _auditingHelper;
protected IAuditingStore AuditingStore;

public AuditingHelper_Tests()
{
_auditingHelper = GetRequiredService<IAuditingHelper>();
}

protected override void AfterAddApplication(IServiceCollection services)
{
AuditingStore = Substitute.For<IAuditingStore>();
services.Replace(ServiceDescriptor.Singleton(AuditingStore));
}

[Fact]
public async Task Should_Write_AuditLog_Without_DisableAuditing()
{
var myAuditedObject = GetRequiredService<MyAuditedObject>();

await myAuditedObject.DoItAsync();

await AuditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}

[Fact]
public async Task Should_Not_Write_AuditLog_With_DisableAuditing()
{
var myAuditedObject = GetRequiredService<MyAuditedObject>();

using (_auditingHelper.DisableAuditing())
{
await myAuditedObject.DoItAsync();
}

await AuditingStore.DidNotReceive().SaveAsync(Arg.Any<AuditLogInfo>());
}

[Fact]
public async Task Should_Write_AuditLog_After_DisableAuditing_Scope_Disposed()
{
var myAuditedObject = GetRequiredService<MyAuditedObject>();

using (_auditingHelper.DisableAuditing())
{
await myAuditedObject.DoItAsync();
}

AuditingStore.ClearReceivedCalls();

await myAuditedObject.DoItAsync();

await AuditingStore.Received().SaveAsync(Arg.Any<AuditLogInfo>());
}

[Fact]
public async Task Should_Not_Write_AuditLog_With_Nested_DisableAuditing()
{
var myAuditedObject = GetRequiredService<MyAuditedObject>();

using (_auditingHelper.DisableAuditing())
{
await myAuditedObject.DoItAsync();

using (_auditingHelper.DisableAuditing())
{
await myAuditedObject.DoItAsync();
}

await myAuditedObject.DoItAsync();
}

await AuditingStore.DidNotReceive().SaveAsync(Arg.Any<AuditLogInfo>());
}

[Fact]
public void Should_Return_True_When_Auditing_Is_Enabled()
{
Assert.True(_auditingHelper.IsAuditingEnabled());
}

[Fact]
public void Should_Return_False_When_Auditing_Is_Disabled()
{
using (_auditingHelper.DisableAuditing())
{
Assert.False(_auditingHelper.IsAuditingEnabled());
}
}

[Fact]
public void Should_Return_True_After_DisableAuditing_Scope_Disposed()
{
using (_auditingHelper.DisableAuditing())
{
Assert.False(_auditingHelper.IsAuditingEnabled());
}

Assert.True(_auditingHelper.IsAuditingEnabled());
}

[Fact]
public void Should_Return_False_With_Nested_DisableAuditing()
{
using (_auditingHelper.DisableAuditing())
{
Assert.False(_auditingHelper.IsAuditingEnabled());

using (_auditingHelper.DisableAuditing())
{
Assert.False(_auditingHelper.IsAuditingEnabled());
}

Assert.False(_auditingHelper.IsAuditingEnabled());
}
}

public interface IMyAuditedObject : ITransientDependency, IAuditingEnabled
{
}

public class MyAuditedObject : IMyAuditedObject
{
public virtual Task DoItAsync()
{
return Task.CompletedTask;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Volo.Abp.Auditing;
using Volo.Abp.Caching;
using Volo.Abp.Features;
using Volo.Abp.MultiTenancy;
Expand All @@ -16,18 +17,21 @@ public class CmsKitPageRouteValueTransformer : CmsKitDynamicRouteValueTransforme
protected IFeatureChecker FeatureChecker { get; }
protected IPagePublicAppService PagePublicAppService { get; }
protected IDistributedCache<PageCacheItem> PageCache { get; }
protected IAuditingHelper AuditingHelper { get; }

public CmsKitPageRouteValueTransformer(
ICurrentTenant currentTenant,
ITenantConfigurationProvider tenantConfigurationProvider,
IFeatureChecker featureChecker,
IPagePublicAppService pagePublicAppService,
IDistributedCache<PageCacheItem> pageCache)
IDistributedCache<PageCacheItem> pageCache,
IAuditingHelper auditingHelper)
: base(currentTenant, tenantConfigurationProvider)
{
FeatureChecker = featureChecker;
PagePublicAppService = pagePublicAppService;
PageCache = pageCache;
AuditingHelper = auditingHelper;
}

protected async override ValueTask<RouteValueDictionary> DoTransformAsync(HttpContext httpContext, RouteValueDictionary values)
Expand All @@ -44,7 +48,10 @@ protected async override ValueTask<RouteValueDictionary> DoTransformAsync(HttpCo
var exist = await PageCache.GetAsync(PageCacheItem.GetKey(slug)) != null;
if (!exist)
{
exist = await PagePublicAppService.DoesSlugExistAsync(slug);
using (AuditingHelper.DisableAuditing())
{
exist = await PagePublicAppService.DoesSlugExistAsync(slug);
}
}

if (exist)
Expand Down
Loading