Introduce the SimpleStateChecker.

pull/8742/head
maliming 5 years ago
parent 3bee88e86c
commit 24498a052d

@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
{
public class ToolbarItem
public class ToolbarItem : IHasSimpleStateCheckers<ToolbarItem>
{
public Type ComponentType
{
@ -15,13 +17,17 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
public int Order { get; set; }
[CanBeNull]
[Obsolete("Use RequirePermissions extension method.")]
public string RequiredPermissionName { get; set; }
public List<ISimpleStateChecker<ToolbarItem>> SimpleStateCheckers { get; }
public ToolbarItem([NotNull] Type componentType, int order = 0, string requiredPermissionName = null)
{
Order = order;
ComponentType = Check.NotNull(componentType, nameof(componentType));
RequiredPermissionName = requiredPermissionName;
SimpleStateCheckers = new List<ISimpleStateChecker<ToolbarItem>>();
}
}
}

@ -7,6 +7,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
{
@ -15,13 +16,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
protected IThemeManager ThemeManager { get; }
protected AbpToolbarOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
protected ISimpleStateCheckerManager<ToolbarItem> SimpleStateCheckerManager { get; }
public ToolbarManager(
IOptions<AbpToolbarOptions> options,
IServiceProvider serviceProvider,
IThemeManager themeManager)
IThemeManager themeManager,
ISimpleStateCheckerManager<ToolbarItem> simpleStateCheckerManager)
{
ThemeManager = themeManager;
SimpleStateCheckerManager = simpleStateCheckerManager;
ServiceProvider = serviceProvider;
Options = options.Value;
}
@ -47,17 +51,20 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars
protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, Toolbar toolbar)
{
var requiredPermissionItems = toolbar.Items.Where(x => !x.RequiredPermissionName.IsNullOrWhiteSpace()).ToList();
foreach (var item in toolbar.Items.Where(x => !x.RequiredPermissionName.IsNullOrWhiteSpace()))
{
item.RequirePermissions(item.RequiredPermissionName);
}
if (requiredPermissionItems.Any())
var checkPermissionsToolbarItems = toolbar.Items.Where(x => x.SimpleStateCheckers.Any()).ToArray();
if (checkPermissionsToolbarItems.Any())
{
var permissionChecker = serviceProvider.GetRequiredService<IPermissionChecker>();
var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).Distinct().ToArray());
var result = await SimpleStateCheckerManager.IsEnabledAsync(checkPermissionsToolbarItems);
var toBeDeleted = new HashSet<ToolbarItem>();
foreach (var item in requiredPermissionItems)
foreach (var item in checkPermissionsToolbarItems)
{
if (grantResult.Result[item.RequiredPermissionName!] != PermissionGrantResult.Granted)
if (!result[item])
{
toBeDeleted.Add(item);
}

@ -8,13 +8,10 @@ namespace Volo.Abp.Authorization.Permissions
public ITypeList<IPermissionValueProvider> ValueProviders { get; }
public ITypeList<IPermissionStateProvider> GlobalStateProviders { get; }
public AbpPermissionOptions()
{
DefinitionProviders = new TypeList<IPermissionDefinitionProvider>();
ValueProviders = new TypeList<IPermissionValueProvider>();
GlobalStateProviders = new TypeList<IPermissionStateProvider>();
}
}
}

@ -1,9 +0,0 @@
using System.Threading.Tasks;
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionStateManager
{
Task<bool> IsEnabledAsync(PermissionDefinition permission);
}
}

@ -1,9 +0,0 @@
using System.Threading.Tasks;
namespace Volo.Abp.Authorization.Permissions
{
public interface IPermissionStateProvider
{
Task<bool> IsEnabledAsync(PermissionStateContext context);
}
}

@ -3,10 +3,11 @@ using System.Collections.Immutable;
using JetBrains.Annotations;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionDefinition
public class PermissionDefinition : IHasSimpleStateCheckers<PermissionDefinition>
{
/// <summary>
/// Unique name of the permission.
@ -31,7 +32,7 @@ namespace Volo.Abp.Authorization.Permissions
/// </summary>
public List<string> Providers { get; } //TODO: Rename to AllowedProviders?
public List<IPermissionStateProvider> StateProviders { get; }
public List<ISimpleStateChecker<PermissionDefinition>> SimpleStateCheckers { get; }
public ILocalizableString DisplayName
{
@ -88,7 +89,7 @@ namespace Volo.Abp.Authorization.Permissions
Properties = new Dictionary<string, object>();
Providers = new List<string>();
StateProviders = new List<IPermissionStateProvider>();
SimpleStateCheckers = new List<ISimpleStateChecker<PermissionDefinition>>();
_children = new List<PermissionDefinition>();
}

@ -1,19 +0,0 @@
using JetBrains.Annotations;
namespace Volo.Abp.Authorization.Permissions
{
public static class PermissionDefinitionExtensions
{
public static PermissionDefinition AddStateProviders(
[NotNull] this PermissionDefinition permissionDefinition,
[NotNull] params IPermissionStateProvider[] permissionStateProviders)
{
Check.NotNull(permissionDefinition, nameof(permissionDefinition));
Check.NotNull(permissionStateProviders, nameof(permissionStateProviders));
permissionDefinition.StateProviders.AddRange(permissionStateProviders);
return permissionDefinition;
}
}
}

@ -0,0 +1,53 @@
using JetBrains.Annotations;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization.Permissions
{
public static class PermissionSimpleStateCheckerExtensions
{
public static TState RequirePermissions<TState>(
[NotNull] this TState state,
params string[] permissions)
where TState : IHasSimpleStateCheckers<TState>
{
state.RequirePermissions(requiresAll: true, batchCheck: true, permissions);
return state;
}
public static TState RequirePermissions<TState>(
[NotNull] this TState state,
bool requiresAll,
params string[] permissions)
where TState : IHasSimpleStateCheckers<TState>
{
state.RequirePermissions(requiresAll: requiresAll, batchCheck: true, permissions);
return state;
}
public static TState RequirePermissions<TState>(
[NotNull] this TState state,
bool requiresAll,
bool batchCheck = true,
params string[] permissions)
where TState : IHasSimpleStateCheckers<TState>
{
Check.NotNull(state, nameof(state));
Check.NotNullOrEmpty(permissions, nameof(permissions));
if (batchCheck)
{
lock (state)
{
RequirePermissionsSimpleBatchStateChecker<TState>.Instance.AddCheckModels(new RequirePermissionsSimpleBatchStateCheckerModel<TState>(state, permissions, requiresAll));
state.SimpleStateCheckers.Add(RequirePermissionsSimpleBatchStateChecker<TState>.Instance);
}
}
else
{
state.SimpleStateCheckers.Add(new RequirePermissionsSimpleStateChecker<TState>(new RequirePermissionsSimpleBatchStateCheckerModel<TState>(state, permissions, requiresAll)));
}
return state;
}
}
}

@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization.Permissions
{
public class RequirePermissionsSimpleBatchStateChecker<TState> : SimpleBatchStateCheckerBase<TState>
where TState : IHasSimpleStateCheckers<TState>
{
public static readonly RequirePermissionsSimpleBatchStateChecker<TState> Instance = new RequirePermissionsSimpleBatchStateChecker<TState>();
private readonly List<RequirePermissionsSimpleBatchStateCheckerModel<TState>> _models;
public RequirePermissionsSimpleBatchStateChecker()
{
_models = new List<RequirePermissionsSimpleBatchStateCheckerModel<TState>>();
}
public RequirePermissionsSimpleBatchStateChecker<TState> AddCheckModels(params RequirePermissionsSimpleBatchStateCheckerModel<TState>[] models)
{
Check.NotNullOrEmpty(models, nameof(models));
_models.AddRange(models);
return this;
}
public override async Task<SimpleStateCheckerResult<TState>> IsEnabledAsync(SimpleBatchStateCheckerContext<TState> context)
{
var permissionChecker = context.ServiceProvider.GetRequiredService<IPermissionChecker>();
var result = new SimpleStateCheckerResult<TState>(context.States);
var permissions = _models.Where(x => context.States.Any(s => s.Equals(x.State))).SelectMany(x => x.Permissions).Distinct().ToArray();
var grantResult = await permissionChecker.IsGrantedAsync(permissions);
foreach (var state in context.States)
{
var model = _models.FirstOrDefault(x => x.State.Equals(state));
if (model != null)
{
if (model.RequiresAll)
{
result[model.State] = model.Permissions.All(x => grantResult.Result.Any(y => y.Key == x && y.Value == PermissionGrantResult.Granted));
}
else
{
result[model.State] = grantResult.Result.Any(x => model.Permissions.Contains(x.Key) && x.Value == PermissionGrantResult.Granted);
}
}
}
return result;
}
}
}

@ -0,0 +1,24 @@
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization.Permissions
{
public class RequirePermissionsSimpleBatchStateCheckerModel<TState>
where TState : IHasSimpleStateCheckers<TState>
{
public TState State { get; }
public string[] Permissions { get; }
public bool RequiresAll { get; }
public RequirePermissionsSimpleBatchStateCheckerModel(TState state, string[] permissions, bool requiresAll = true)
{
Check.NotNull(state, nameof(state));
Check.NotNullOrEmpty(permissions, nameof(permissions));
State = state;
Permissions = permissions;
RequiresAll = requiresAll;
}
}
}

@ -0,0 +1,34 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization.Permissions
{
public class RequirePermissionsSimpleStateChecker<TState> : ISimpleStateChecker<TState>
where TState : IHasSimpleStateCheckers<TState>
{
private readonly RequirePermissionsSimpleBatchStateCheckerModel<TState> _model;
public RequirePermissionsSimpleStateChecker(RequirePermissionsSimpleBatchStateCheckerModel<TState> model)
{
_model = model;
}
public async Task<bool> IsEnabledAsync(SimpleStateCheckerContext<TState> context)
{
var permissionChecker = context.ServiceProvider.GetRequiredService<IPermissionChecker>();
if (_model.Permissions.Length == 1)
{
return await permissionChecker.IsGrantedAsync(_model.Permissions.First());
}
var grantResult = await permissionChecker.IsGrantedAsync(_model.Permissions);
return _model.RequiresAll
? grantResult.AllGranted
: grantResult.Result.Any(x => _model.Permissions.Contains(x.Key) && x.Value == PermissionGrantResult.Granted);
}
}
}

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization.Permissions
{
@ -15,20 +16,20 @@ namespace Volo.Abp.Authorization.Permissions
protected ICurrentPrincipalAccessor PrincipalAccessor { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IPermissionValueProviderManager PermissionValueProviderManager { get; }
protected IPermissionStateManager PermissionStateManager { get; }
protected ISimpleStateCheckerManager<PermissionDefinition> PermissionSimpleStateCheckerManager { get; }
public PermissionChecker(
ICurrentPrincipalAccessor principalAccessor,
IPermissionDefinitionManager permissionDefinitionManager,
ICurrentTenant currentTenant,
IPermissionValueProviderManager permissionValueProviderManager,
IPermissionStateManager permissionStateManager)
ISimpleStateCheckerManager<PermissionDefinition> permissionSimpleStateCheckerManager)
{
PrincipalAccessor = principalAccessor;
PermissionDefinitionManager = permissionDefinitionManager;
CurrentTenant = currentTenant;
PermissionValueProviderManager = permissionValueProviderManager;
PermissionStateManager = permissionStateManager;
PermissionSimpleStateCheckerManager = permissionSimpleStateCheckerManager;
}
public virtual async Task<bool> IsGrantedAsync(string name)
@ -49,7 +50,7 @@ namespace Volo.Abp.Authorization.Permissions
return false;
}
if (!await PermissionStateManager.IsEnabledAsync(permission))
if (!await PermissionSimpleStateCheckerManager.IsEnabledAsync(permission))
{
return false;
}
@ -112,7 +113,7 @@ namespace Volo.Abp.Authorization.Permissions
result.Result.Add(name, PermissionGrantResult.Undefined);
if (permission.IsEnabled &&
await PermissionStateManager.IsEnabledAsync(permission) &&
await PermissionSimpleStateCheckerManager.IsEnabledAsync(permission) &&
permission.MultiTenancySide.HasFlag(multiTenancySide))
{
permissionDefinitions.Add(permission);

@ -1,51 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Authorization.Permissions
{
public class PermissionStateManager : IPermissionStateManager, ITransientDependency
{
protected IServiceProvider ServiceProvider { get; }
protected AbpPermissionOptions Options { get; }
public PermissionStateManager(IServiceProvider serviceProvider, IOptions<AbpPermissionOptions> options)
{
ServiceProvider = serviceProvider;
Options = options.Value;
}
public async Task<bool> IsEnabledAsync(PermissionDefinition permission)
{
using (var scope = ServiceProvider.CreateScope())
{
var context = new PermissionStateContext
{
Permission = permission,
ServiceProvider = scope.ServiceProvider.GetRequiredService<ICachedServiceProvider>()
};
foreach (var provider in permission.StateProviders)
{
if (!await provider.IsEnabledAsync(context))
{
return false;
}
}
foreach (IPermissionStateProvider provider in Options.GlobalStateProviders.Select(x => ServiceProvider.GetRequiredService(x)))
{
if (!await provider.IsEnabledAsync(context))
{
return false;
}
}
return true;
}
}
}
}

@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Logging;
using Volo.Abp.Modularity;
using Volo.Abp.Reflection;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Internal
{
@ -40,6 +41,8 @@ namespace Volo.Abp.Internal
services.AddAssemblyOf<IAbpApplication>();
services.AddTransient(typeof(ISimpleStateCheckerManager<>), typeof(SimpleStateCheckerManager<>));
services.Configure<AbpModuleLifecycleOptions>(options =>
{
options.Contributors.Add<OnPreApplicationInitializationModuleLifecycleContributor>();

@ -0,0 +1,15 @@
using Volo.Abp.Collections;
namespace Volo.Abp.SimpleStateChecking
{
public class AbpSimpleStateCheckerOptions<TState>
where TState : IHasSimpleStateCheckers<TState>
{
public ITypeList<ISimpleStateChecker<TState>> GlobalSimpleStateCheckers { get; }
public AbpSimpleStateCheckerOptions()
{
GlobalSimpleStateCheckers = new TypeList<ISimpleStateChecker<TState>>();
}
}
}

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Volo.Abp.SimpleStateChecking
{
public interface IHasSimpleStateCheckers<TState>
where TState : IHasSimpleStateCheckers<TState>
{
List<ISimpleStateChecker<TState>> SimpleStateCheckers { get; }
}
}

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace Volo.Abp.SimpleStateChecking
{
public interface ISimpleBatchStateChecker<TState> : ISimpleStateChecker<TState>
where TState : IHasSimpleStateCheckers<TState>
{
Task<SimpleStateCheckerResult<TState>> IsEnabledAsync(SimpleBatchStateCheckerContext<TState> context);
}
}

@ -0,0 +1,10 @@
using System.Threading.Tasks;
namespace Volo.Abp.SimpleStateChecking
{
public interface ISimpleStateChecker<TState>
where TState : IHasSimpleStateCheckers<TState>
{
Task<bool> IsEnabledAsync(SimpleStateCheckerContext<TState> context);
}
}

@ -0,0 +1,12 @@
using System.Threading.Tasks;
namespace Volo.Abp.SimpleStateChecking
{
public interface ISimpleStateCheckerManager<TState>
where TState : IHasSimpleStateCheckers<TState>
{
Task<bool> IsEnabledAsync(TState state);
Task<SimpleStateCheckerResult<TState>> IsEnabledAsync(TState[] states);
}
}

@ -0,0 +1,16 @@
using System.Linq;
using System.Threading.Tasks;
namespace Volo.Abp.SimpleStateChecking
{
public abstract class SimpleBatchStateCheckerBase<TState>: ISimpleBatchStateChecker<TState>
where TState : IHasSimpleStateCheckers<TState>
{
public async Task<bool> IsEnabledAsync(SimpleStateCheckerContext<TState> context)
{
return (await IsEnabledAsync(new SimpleBatchStateCheckerContext<TState>(context.ServiceProvider, new[] {context.State}))).Values.All(x => x);
}
public abstract Task<SimpleStateCheckerResult<TState>> IsEnabledAsync(SimpleBatchStateCheckerContext<TState> context);
}
}

@ -0,0 +1,18 @@
using System;
namespace Volo.Abp.SimpleStateChecking
{
public class SimpleBatchStateCheckerContext<TState>
where TState : IHasSimpleStateCheckers<TState>
{
public IServiceProvider ServiceProvider { get; }
public TState[] States { get; }
public SimpleBatchStateCheckerContext(IServiceProvider serviceProvider, TState[] states)
{
ServiceProvider = serviceProvider;
States = states;
}
}
}

@ -0,0 +1,18 @@
using System;
namespace Volo.Abp.SimpleStateChecking
{
public class SimpleStateCheckerContext<TState>
where TState : IHasSimpleStateCheckers<TState>
{
public IServiceProvider ServiceProvider { get; }
public TState State { get; }
public SimpleStateCheckerContext(IServiceProvider serviceProvider, TState state)
{
ServiceProvider = serviceProvider;
State = state;
}
}
}

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.SimpleStateChecking
{
public class SimpleStateCheckerManager<TState> : ISimpleStateCheckerManager<TState>
where TState : IHasSimpleStateCheckers<TState>
{
protected IServiceProvider ServiceProvider { get; }
protected AbpSimpleStateCheckerOptions<TState> Options { get; }
public SimpleStateCheckerManager(IServiceProvider serviceProvider, IOptions<AbpSimpleStateCheckerOptions<TState>> options)
{
ServiceProvider = serviceProvider;
Options = options.Value;
}
public virtual async Task<bool> IsEnabledAsync(TState state)
{
return await InternalIsEnabledAsync(state, true);
}
public virtual async Task<SimpleStateCheckerResult<TState>> IsEnabledAsync(TState[] states)
{
var result = new SimpleStateCheckerResult<TState>(states);
using (var scope = ServiceProvider.CreateScope())
{
var batchStateCheckers = states.SelectMany(x => x.SimpleStateCheckers)
.Where(x => x is ISimpleBatchStateChecker<TState>)
.Cast<ISimpleBatchStateChecker<TState>>()
.GroupBy(x => x)
.Select(x => x.Key);
foreach (var stateChecker in batchStateCheckers)
{
var context = new SimpleBatchStateCheckerContext<TState>(
scope.ServiceProvider.GetRequiredService<ICachedServiceProvider>(),
states.Where(x => x.SimpleStateCheckers.Contains(stateChecker)).ToArray());
foreach (var x in await stateChecker.IsEnabledAsync(context))
{
result[x.Key] = x.Value;
}
if (result.Values.All(x => !x))
{
return result;
}
}
foreach (ISimpleBatchStateChecker<TState> globalStateChecker in Options.GlobalSimpleStateCheckers
.Where(x => typeof(ISimpleBatchStateChecker<TState>).IsAssignableFrom(x))
.Select(x => ServiceProvider.GetRequiredService(x)))
{
var context = new SimpleBatchStateCheckerContext<TState>(
scope.ServiceProvider.GetRequiredService<ICachedServiceProvider>(),
states.Where(x => result.Any(y => y.Key.Equals(x) && y.Value)).ToArray());
foreach (var x in await globalStateChecker.IsEnabledAsync(context))
{
result[x.Key] = x.Value;
}
}
foreach (var state in states)
{
if (result[state])
{
result[state] = await InternalIsEnabledAsync(state, false);
}
}
return result;
}
}
protected virtual async Task<bool> InternalIsEnabledAsync(TState state, bool useBatchChecker)
{
using (var scope = ServiceProvider.CreateScope())
{
var context = new SimpleStateCheckerContext<TState>(scope.ServiceProvider.GetRequiredService<ICachedServiceProvider>(), state);
foreach (var provider in state.SimpleStateCheckers.WhereIf(!useBatchChecker, x => x is not ISimpleBatchStateChecker<TState>))
{
if (!await provider.IsEnabledAsync(context))
{
return false;
}
}
foreach (ISimpleStateChecker<TState> provider in Options.GlobalSimpleStateCheckers
.WhereIf(!useBatchChecker, x => !typeof(ISimpleBatchStateChecker<TState>).IsAssignableFrom(x))
.Select(x => ServiceProvider.GetRequiredService(x)))
{
if (!await provider.IsEnabledAsync(context))
{
return false;
}
}
return true;
}
}
}
}

@ -0,0 +1,21 @@
using System.Collections.Generic;
namespace Volo.Abp.SimpleStateChecking
{
public class SimpleStateCheckerResult<TState> : Dictionary<TState, bool>
where TState : IHasSimpleStateCheckers<TState>
{
public SimpleStateCheckerResult()
{
}
public SimpleStateCheckerResult(IEnumerable<TState> states, bool initValue = true)
{
foreach (var state in states)
{
Add(state, initValue);
}
}
}
}

@ -0,0 +1,30 @@
using JetBrains.Annotations;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Features
{
public static class FeatureSimpleStateCheckerExtensions
{
public static TState RequireFeatures<TState>(
[NotNull] this TState state,
params string[] features)
where TState : IHasSimpleStateCheckers<TState>
{
state.RequireFeatures(true, features);
return state;
}
public static TState RequireFeatures<TState>(
[NotNull] this TState state,
bool requiresAll,
params string[] features)
where TState : IHasSimpleStateCheckers<TState>
{
Check.NotNull(state, nameof(state));
Check.NotNullOrEmpty(features, nameof(features));
state.SimpleStateCheckers.Add(new RequireFeaturesSimpleStateChecker<TState>(requiresAll, features));
return state;
}
}
}

@ -1,28 +0,0 @@
using JetBrains.Annotations;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.Features
{
public static class FeatureDefinitionExtensions
{
public static PermissionDefinition RequireFeatures(
[NotNull] this PermissionDefinition permissionDefinition,
params string[] features)
{
return permissionDefinition.RequireFeatures(true, features);
}
public static PermissionDefinition RequireFeatures(
[NotNull] this PermissionDefinition permissionDefinition,
bool requiresAll,
params string[] features)
{
Check.NotNull(permissionDefinition, nameof(permissionDefinition));
Check.NotNullOrEmpty(features, nameof(features));
return permissionDefinition.AddStateProviders(
new RequireFeaturesPermissionStateProvider(requiresAll, features)
);
}
}
}

@ -1,32 +0,0 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.Features
{
public class RequireFeaturesPermissionStateProvider : IPermissionStateProvider
{
private readonly string[] _featureNames;
private readonly bool _requiresAll;
public RequireFeaturesPermissionStateProvider(params string[] featureNames)
: this(true, featureNames)
{
}
public RequireFeaturesPermissionStateProvider(bool requiresAll, params string[] featureNames)
{
Check.NotNullOrEmpty(featureNames, nameof(featureNames));
_requiresAll = requiresAll;
_featureNames = featureNames;
}
public async Task<bool> IsEnabledAsync(PermissionStateContext context)
{
var feature = context.ServiceProvider.GetRequiredService<IFeatureChecker>();
return await feature.IsEnabledAsync(_requiresAll, _featureNames);
}
}
}

@ -0,0 +1,32 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Features
{
public class RequireFeaturesSimpleStateChecker<TState> : ISimpleStateChecker<TState>
where TState : IHasSimpleStateCheckers<TState>
{
private readonly string[] _featureNames;
private readonly bool _requiresAll;
public RequireFeaturesSimpleStateChecker(params string[] featureNames)
: this(true, featureNames)
{
}
public RequireFeaturesSimpleStateChecker(bool requiresAll, params string[] featureNames)
{
Check.NotNullOrEmpty(featureNames, nameof(featureNames));
_requiresAll = requiresAll;
_featureNames = featureNames;
}
public async Task<bool> IsEnabledAsync(SimpleStateCheckerContext<TState> context)
{
var featureChecker = context.ServiceProvider.GetRequiredService<IFeatureChecker>();
return await featureChecker.IsEnabledAsync(_requiresAll, _featureNames);
}
}
}

@ -1,50 +0,0 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.GlobalFeatures
{
public static class GlobalFeatureDefinitionExtensions
{
public static PermissionDefinition RequireGlobalFeatures(
this PermissionDefinition permissionDefinition,
params string[] globalFeatures)
{
return permissionDefinition.RequireGlobalFeatures(true, globalFeatures);
}
public static PermissionDefinition RequireGlobalFeatures(
[NotNull] this PermissionDefinition permissionDefinition,
bool requiresAll,
params string[] globalFeatures)
{
Check.NotNull(permissionDefinition, nameof(permissionDefinition));
Check.NotNullOrEmpty(globalFeatures, nameof(globalFeatures));
return permissionDefinition.AddStateProviders(
new RequireGlobalFeaturesPermissionStateProvider(requiresAll, globalFeatures)
);
}
public static PermissionDefinition RequireGlobalFeatures(
this PermissionDefinition permissionDefinition,
params Type[] globalFeatures)
{
return permissionDefinition.RequireGlobalFeatures(true, globalFeatures);
}
public static PermissionDefinition RequireGlobalFeatures(
[NotNull] this PermissionDefinition permissionDefinition,
bool requiresAll,
params Type[] globalFeatures)
{
Check.NotNull(permissionDefinition, nameof(permissionDefinition));
Check.NotNullOrEmpty(globalFeatures, nameof(globalFeatures));
return permissionDefinition.AddStateProviders(
new RequireGlobalFeaturesPermissionStateProvider(requiresAll, globalFeatures)
);
}
}
}

@ -0,0 +1,51 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.GlobalFeatures
{
public static class GlobalFeatureSimpleStateCheckerExtensions
{
public static TState RequireGlobalFeatures<TState>(
[NotNull] this TState state,
params string[] globalFeatures)
where TState : IHasSimpleStateCheckers<TState>
{
return state.RequireGlobalFeatures(true, globalFeatures);
}
public static TState RequireGlobalFeatures<TState>(
[NotNull] this TState state,
bool requiresAll,
params string[] globalFeatures)
where TState : IHasSimpleStateCheckers<TState>
{
Check.NotNull(state, nameof(state));
Check.NotNullOrEmpty(globalFeatures, nameof(globalFeatures));
state.SimpleStateCheckers.Add(new RequireGlobalFeaturesSimpleStateChecker<TState>(requiresAll, globalFeatures));
return state;
}
public static TState RequireGlobalFeatures<TState>(
[NotNull] this TState state,
params Type[] globalFeatures)
where TState : IHasSimpleStateCheckers<TState>
{
return state.RequireGlobalFeatures(true, globalFeatures);
}
public static TState RequireGlobalFeatures<TState>(
[NotNull] this TState state,
bool requiresAll,
params Type[] globalFeatures)
where TState : IHasSimpleStateCheckers<TState>
{
Check.NotNull(state, nameof(state));
Check.NotNullOrEmpty(globalFeatures, nameof(globalFeatures));
state.SimpleStateCheckers.Add(new RequireGlobalFeaturesSimpleStateChecker<TState>(requiresAll, globalFeatures));
return state;
}
}
}

@ -1,21 +1,22 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.GlobalFeatures
{
public class RequireGlobalFeaturesPermissionStateProvider : IPermissionStateProvider
public class RequireGlobalFeaturesSimpleStateChecker<TState> : ISimpleStateChecker<TState>
where TState : IHasSimpleStateCheckers<TState>
{
private readonly string[] _globalFeatureNames;
private readonly bool _requiresAll;
public RequireGlobalFeaturesPermissionStateProvider(params string[] globalFeatureNames)
public RequireGlobalFeaturesSimpleStateChecker(params string[] globalFeatureNames)
: this(true, globalFeatureNames)
{
}
public RequireGlobalFeaturesPermissionStateProvider(bool requiresAll, params string[] globalFeatureNames)
public RequireGlobalFeaturesSimpleStateChecker(bool requiresAll, params string[] globalFeatureNames)
{
Check.NotNullOrEmpty(globalFeatureNames, nameof(globalFeatureNames));
@ -23,7 +24,7 @@ namespace Volo.Abp.GlobalFeatures
_globalFeatureNames = globalFeatureNames;
}
public RequireGlobalFeaturesPermissionStateProvider(bool requiresAll, params Type[] globalFeatureNames)
public RequireGlobalFeaturesSimpleStateChecker(bool requiresAll, params Type[] globalFeatureNames)
{
Check.NotNullOrEmpty(globalFeatureNames, nameof(globalFeatureNames));
@ -31,9 +32,9 @@ namespace Volo.Abp.GlobalFeatures
_globalFeatureNames = globalFeatureNames.Select(GlobalFeatureNameAttribute.GetName).ToArray();
}
public Task<bool> IsEnabledAsync(PermissionStateContext context)
public Task<bool> IsEnabledAsync(SimpleStateCheckerContext<TState> context)
{
bool isEnabled = _requiresAll
var isEnabled = _requiresAll
? _globalFeatureNames.All(x => GlobalFeatureManager.Instance.IsEnabled(x))
: _globalFeatureNames.Any(x => GlobalFeatureManager.Instance.IsEnabled(x));

@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.UI.Navigation
{
public class ApplicationMenuItem : IHasMenuItems
public class ApplicationMenuItem : IHasMenuItems, IHasSimpleStateCheckers<ApplicationMenuItem>
{
private string _displayName;
@ -72,8 +73,11 @@ namespace Volo.Abp.UI.Navigation
public ApplicationMenuItemList Items { get; }
[CanBeNull]
[Obsolete("Use RequirePermissions extension method.")]
public string RequiredPermissionName { get; set; }
public List<ISimpleStateChecker<ApplicationMenuItem>> SimpleStateCheckers { get; }
/// <summary>
/// Can be used to store a custom object related to this menu item. Optional.
/// </summary>
@ -114,7 +118,7 @@ namespace Volo.Abp.UI.Navigation
ElementId = elementId ?? GetDefaultElementId();
CssClass = cssClass;
RequiredPermissionName = requiredPermissionName;
SimpleStateCheckers = new List<ISimpleStateChecker<ApplicationMenuItem>>();
Items = new ApplicationMenuItemList();
}

@ -2,10 +2,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.UI.Navigation
{
@ -13,13 +13,16 @@ namespace Volo.Abp.UI.Navigation
{
protected AbpNavigationOptions Options { get; }
protected IHybridServiceScopeFactory ServiceScopeFactory { get; }
protected ISimpleStateCheckerManager<ApplicationMenuItem> SimpleStateCheckerManager { get; }
public MenuManager(
IOptions<AbpNavigationOptions> options,
IHybridServiceScopeFactory serviceScopeFactory)
IHybridServiceScopeFactory serviceScopeFactory,
ISimpleStateCheckerManager<ApplicationMenuItem> simpleStateCheckerManager)
{
ServiceScopeFactory = serviceScopeFactory;
Options = options.Value;
ServiceScopeFactory = serviceScopeFactory;
SimpleStateCheckerManager = simpleStateCheckerManager;
}
public async Task<ApplicationMenu> GetAsync(string name)
@ -45,18 +48,26 @@ namespace Volo.Abp.UI.Navigation
protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, IHasMenuItems menuWithItems)
{
var requiredPermissionItems = new List<ApplicationMenuItem>();
GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionItems);
var allMenuItems = new List<ApplicationMenuItem>();
GetAllMenuItems(menuWithItems, allMenuItems);
if (requiredPermissionItems.Any())
foreach (var item in allMenuItems)
{
var permissionChecker = serviceProvider.GetRequiredService<IPermissionChecker>();
var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).Distinct().ToArray());
if (!item.RequiredPermissionName.IsNullOrWhiteSpace())
{
item.RequirePermissions(item.RequiredPermissionName);
}
}
var checkPermissionsMenuItems = allMenuItems.Where(x => x.SimpleStateCheckers.Any()).ToArray();
if (checkPermissionsMenuItems.Any())
{
var toBeDeleted = new HashSet<ApplicationMenuItem>();
foreach (var menu in requiredPermissionItems)
var result = await SimpleStateCheckerManager.IsEnabledAsync(checkPermissionsMenuItems);
foreach (var menu in checkPermissionsMenuItems)
{
if (grantResult.Result[menu.RequiredPermissionName!] != PermissionGrantResult.Granted)
if (!result[menu])
{
toBeDeleted.Add(menu);
}
@ -66,16 +77,12 @@ namespace Volo.Abp.UI.Navigation
}
}
protected virtual void GetRequiredPermissionNameMenus(IHasMenuItems menuWithItems, List<ApplicationMenuItem> output)
protected virtual void GetAllMenuItems(IHasMenuItems menuWithItems, List<ApplicationMenuItem> output)
{
foreach (var item in menuWithItems.Items)
{
if (!item.RequiredPermissionName.IsNullOrWhiteSpace())
{
output.Add(item);
}
GetRequiredPermissionNameMenus(item, output);
output.Add(item);
GetAllMenuItems(item, output);
}
}

@ -11,6 +11,7 @@ using NSubstitute;
using Shouldly;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars;
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Security.Claims;
using Xunit;
@ -71,8 +72,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.
return Task.CompletedTask;
}
context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent1), requiredPermissionName: "MyComponent1"));
context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent2), requiredPermissionName: "MyComponent2"));
context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent1)).RequirePermissions("MyComponent1"));
context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent2)).RequirePermissions("MyComponent2"));
return Task.CompletedTask;
}
@ -87,7 +88,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.
return Task.CompletedTask;
}
context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent3), requiredPermissionName: "MyComponent3"));
context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent3)).RequirePermissions("MyComponent3"));
context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent4)));
return Task.CompletedTask;

@ -5,19 +5,20 @@ using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Security.Claims;
using Volo.Abp.SimpleStateChecking;
using Xunit;
namespace Volo.Abp.Authorization
{
public abstract class PermissionStateProvider_Tests : AuthorizationTestBase
{
protected IPermissionStateManager PermissionStateManager { get; }
protected ISimpleStateCheckerManager<PermissionDefinition> PermissionSimpleStateCheckerManager { get; }
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
protected ICurrentPrincipalAccessor CurrentPrincipalAccessor { get; }
public PermissionStateProvider_Tests()
{
PermissionStateManager = GetRequiredService<IPermissionStateManager>();
PermissionSimpleStateCheckerManager = GetRequiredService<ISimpleStateCheckerManager<PermissionDefinition>>();
PermissionDefinitionManager = GetRequiredService<IPermissionDefinitionManager>();
CurrentPrincipalAccessor = GetRequiredService<ICurrentPrincipalAccessor>();
}
@ -29,13 +30,13 @@ namespace Volo.Abp.Authorization
public async Task PermissionState_Test()
{
var myPermission1 = PermissionDefinitionManager.Get("MyPermission1");
myPermission1.StateProviders.ShouldContain(x => x.GetType() == typeof(TestRequireEditionPermissionStateProvider));
myPermission1.SimpleStateCheckers.ShouldContain(x => x.GetType() == typeof(TestRequireEditionPermissionSimpleStateChecker));
(await PermissionStateManager.IsEnabledAsync(myPermission1)).ShouldBeFalse();
(await PermissionSimpleStateCheckerManager.IsEnabledAsync(myPermission1)).ShouldBeFalse();
using (CurrentPrincipalAccessor.Change(new Claim(AbpClaimTypes.EditionId, Guid.NewGuid().ToString())))
{
(await PermissionStateManager.IsEnabledAsync(myPermission1)).ShouldBeTrue();
(await PermissionSimpleStateCheckerManager.IsEnabledAsync(myPermission1)).ShouldBeTrue();
}
}
}
@ -44,7 +45,10 @@ namespace Volo.Abp.Authorization
{
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpPermissionOptions>(options => options.GlobalStateProviders.Add<TestGlobalRequireRolePermissionStateProvider>());
services.Configure<AbpSimpleStateCheckerOptions<PermissionDefinition>>(options =>
{
options.GlobalSimpleStateCheckers.Add<TestGlobalRequireRolePermissionSimpleStateChecker>();
});
}
[Fact]
@ -52,11 +56,11 @@ namespace Volo.Abp.Authorization
{
var myPermission2 = PermissionDefinitionManager.Get("MyPermission2");
(await PermissionStateManager.IsEnabledAsync(myPermission2)).ShouldBeFalse();
(await PermissionSimpleStateCheckerManager.IsEnabledAsync(myPermission2)).ShouldBeFalse();
using (CurrentPrincipalAccessor.Change(new Claim(AbpClaimTypes.Role, "admin")))
{
(await PermissionStateManager.IsEnabledAsync(myPermission2)).ShouldBeTrue();
(await PermissionSimpleStateCheckerManager.IsEnabledAsync(myPermission2)).ShouldBeTrue();
}
}
}

@ -3,12 +3,13 @@ using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization
{
public class TestGlobalRequireRolePermissionStateProvider : IPermissionStateProvider, ITransientDependency
public class TestGlobalRequireRolePermissionSimpleStateChecker : ISimpleStateChecker<PermissionDefinition>, ITransientDependency
{
public Task<bool> IsEnabledAsync(PermissionStateContext context)
public Task<bool> IsEnabledAsync(SimpleStateCheckerContext<PermissionDefinition> context)
{
var currentPrincipalAccessor = context.ServiceProvider.GetRequiredService<ICurrentPrincipalAccessor>();
return Task.FromResult(currentPrincipalAccessor.Principal != null && currentPrincipalAccessor.Principal.IsInRole("admin"));

@ -3,12 +3,13 @@ using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Security.Claims;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.Authorization
{
public class TestRequireEditionPermissionStateProvider : IPermissionStateProvider
public class TestRequireEditionPermissionSimpleStateChecker : ISimpleStateChecker<PermissionDefinition>
{
public Task<bool> IsEnabledAsync(PermissionStateContext context)
public Task<bool> IsEnabledAsync(SimpleStateCheckerContext<PermissionDefinition> context)
{
var currentPrincipalAccessor = context.ServiceProvider.GetRequiredService<ICurrentPrincipalAccessor>();
return Task.FromResult(currentPrincipalAccessor.Principal?.FindEditionId() != null);

@ -17,7 +17,7 @@ namespace Volo.Abp.Authorization.TestServices
group.AddPermission("MyAuthorizedService1");
group.AddPermission("MyPermission1").AddStateProviders(new TestRequireEditionPermissionStateProvider());
group.AddPermission("MyPermission1").SimpleStateCheckers.Add(new TestRequireEditionPermissionSimpleStateChecker());
group.AddPermission("MyPermission2");
group.GetPermissionOrNull("MyAuthorizedService1").ShouldNotBeNull();

@ -0,0 +1,9 @@
using Volo.Abp.Modularity;
namespace Volo.Abp
{
public class AbpTestModule : AbpModule
{
}
}

@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Testing;
namespace Volo.Abp.SimpleStateChecking
{
public abstract class SimpleStateCheckerTestBase : AbpIntegratedTest<AbpTestModule>
{
protected readonly ISimpleStateCheckerManager<MyStateEntity> SimpleStateCheckerManager;
public SimpleStateCheckerTestBase()
{
SimpleStateCheckerManager = GetRequiredService<ISimpleStateCheckerManager<MyStateEntity>>();
}
public class MyStateEntity : IHasSimpleStateCheckers<MyStateEntity>
{
public int CheckCount { get; set; }
public int GlobalCheckCount { get; set; }
public int MultipleCheckCount { get; set; }
public int MultipleGlobalCheckCount { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? LastModificationTime { get; set; }
public List<ISimpleStateChecker<MyStateEntity>> SimpleStateCheckers { get; }
public MyStateEntity()
{
SimpleStateCheckers = new List<ISimpleStateChecker<MyStateEntity>>();
}
public MyStateEntity AddSimpleStateChecker(ISimpleStateChecker<MyStateEntity> checker)
{
SimpleStateCheckers.Add(checker);
return this;
}
}
public class MySimpleStateChecker : ISimpleStateChecker<SimpleStateCheckerTestBase.MyStateEntity>
{
public Task<bool> IsEnabledAsync(SimpleStateCheckerContext<SimpleStateCheckerTestBase.MyStateEntity> context)
{
context.State.CheckCount += 1;
return Task.FromResult(context.State.CreationTime > DateTime.Parse("2020-01-01", CultureInfo.InvariantCulture));
}
}
public class MyGlobalSimpleStateChecker : ISimpleStateChecker<SimpleStateCheckerTestBase.MyStateEntity>, ITransientDependency
{
public Task<bool> IsEnabledAsync(SimpleStateCheckerContext<SimpleStateCheckerTestBase.MyStateEntity> context)
{
context.State.GlobalCheckCount += 1;
return Task.FromResult(context.State.LastModificationTime.HasValue);
}
}
public class MySimpleBatchStateChecker : SimpleBatchStateCheckerBase<SimpleStateCheckerTestBase.MyStateEntity>
{
public override Task<SimpleStateCheckerResult<SimpleStateCheckerTestBase.MyStateEntity>> IsEnabledAsync(SimpleBatchStateCheckerContext<SimpleStateCheckerTestBase.MyStateEntity> context)
{
foreach (var state in context.States)
{
state.MultipleCheckCount += 1;
}
var result = new SimpleStateCheckerResult<SimpleStateCheckerTestBase.MyStateEntity>(context.States);
foreach (var x in result)
{
result[x.Key] = x.Key.CreationTime > DateTime.Parse("2020-01-01", CultureInfo.InvariantCulture);
}
return Task.FromResult(result);
}
}
public class MyGlobalSimpleBatchStateChecker : SimpleBatchStateCheckerBase<SimpleStateCheckerTestBase.MyStateEntity>, ITransientDependency
{
public override Task<SimpleStateCheckerResult<SimpleStateCheckerTestBase.MyStateEntity>> IsEnabledAsync(SimpleBatchStateCheckerContext<SimpleStateCheckerTestBase.MyStateEntity> context)
{
foreach (var state in context.States)
{
state.MultipleGlobalCheckCount += 1;
}
var result = new SimpleStateCheckerResult<SimpleStateCheckerTestBase.MyStateEntity>(context.States);
foreach (var x in result)
{
result[x.Key] = x.Key.LastModificationTime.HasValue;
}
return Task.FromResult(result);
}
}
}
}

@ -0,0 +1,81 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Shouldly;
using Xunit;
namespace Volo.Abp.SimpleStateChecking
{
public class SimpleStateChecker_CheckCount_Test : SimpleStateCheckerTestBase
{
[Fact]
public async Task Simple_State_Check_Should_Be_Prevent_Multiple_Checks()
{
var myStateEntities = new SimpleStateCheckerTestBase.MyStateEntity[]
{
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2022-01-01", CultureInfo.InvariantCulture)
},
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2020-01-01", CultureInfo.InvariantCulture),
}
};
myStateEntities[0].AddSimpleStateChecker(new MySimpleBatchStateChecker());
myStateEntities[1].AddSimpleStateChecker(new MySimpleStateChecker());
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities[0])).ShouldBeTrue();
myStateEntities[0].CheckCount.ShouldBe(0);
myStateEntities[0].GlobalCheckCount.ShouldBe(0);
myStateEntities[0].MultipleCheckCount.ShouldBe(1);
myStateEntities[0].MultipleGlobalCheckCount.ShouldBe(0);
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities[1])).ShouldBeFalse();
myStateEntities[1].CheckCount.ShouldBe(1);
myStateEntities[1].GlobalCheckCount.ShouldBe(0);
myStateEntities[1].MultipleCheckCount.ShouldBe(0);
myStateEntities[1].MultipleGlobalCheckCount.ShouldBe(0);
}
[Fact]
public async Task Multiple_And_Simple_State_Check_Should_Be_Prevent_Multiple_Checks()
{
var myStateEntities = new SimpleStateCheckerTestBase.MyStateEntity[]
{
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2022-01-01", CultureInfo.InvariantCulture)
},
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2020-01-01", CultureInfo.InvariantCulture),
}
};
myStateEntities[0].AddSimpleStateChecker(new MySimpleBatchStateChecker());
myStateEntities[1].AddSimpleStateChecker(new MySimpleStateChecker());
var result = await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities);
result.Count.ShouldBe(2);
result[myStateEntities[0]].ShouldBeTrue();
result[myStateEntities[1]].ShouldBeFalse();
myStateEntities[0].CheckCount.ShouldBe(0);
myStateEntities[0].GlobalCheckCount.ShouldBe(0);
myStateEntities[0].MultipleCheckCount.ShouldBe(1);
myStateEntities[0].MultipleGlobalCheckCount.ShouldBe(0);
myStateEntities[1].CheckCount.ShouldBe(1);
myStateEntities[1].GlobalCheckCount.ShouldBe(0);
myStateEntities[1].MultipleCheckCount.ShouldBe(0);
myStateEntities[1].MultipleGlobalCheckCount.ShouldBe(0);
}
}
}

@ -0,0 +1,95 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
namespace Volo.Abp.SimpleStateChecking
{
public class SimpleStateChecker_GlobalCheckCount_Test : SimpleStateCheckerTestBase
{
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpSimpleStateCheckerOptions<MyStateEntity>>(options =>
{
options.GlobalSimpleStateCheckers.Add<MyGlobalSimpleStateChecker>();
options.GlobalSimpleStateCheckers.Add<MyGlobalSimpleBatchStateChecker>();
});
base.AfterAddApplication(services);
}
[Fact]
public async Task Simple_State_Check_Should_Be_Prevent_Multiple_Checks()
{
var myStateEntities = new SimpleStateCheckerTestBase.MyStateEntity[]
{
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2022-01-01", CultureInfo.InvariantCulture),
LastModificationTime = DateTime.Parse("2022-01-01", CultureInfo.InvariantCulture)
},
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2020-01-01", CultureInfo.InvariantCulture)
}
};
myStateEntities[0].AddSimpleStateChecker(new MySimpleBatchStateChecker());
myStateEntities[1].AddSimpleStateChecker(new MySimpleStateChecker());
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities[0])).ShouldBeTrue();
myStateEntities[0].CheckCount.ShouldBe(0);
myStateEntities[0].GlobalCheckCount.ShouldBe(1);
myStateEntities[0].MultipleCheckCount.ShouldBe(1);
myStateEntities[0].MultipleGlobalCheckCount.ShouldBe(1);
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities[1])).ShouldBeFalse();
myStateEntities[1].CheckCount.ShouldBe(1);
myStateEntities[1].GlobalCheckCount.ShouldBe(0);
myStateEntities[1].MultipleCheckCount.ShouldBe(0);
myStateEntities[1].MultipleGlobalCheckCount.ShouldBe(0);
}
[Fact]
public async Task Multiple_And_Simple_State_Check_Should_Be_Prevent_Multiple_Checks()
{
var myStateEntities = new SimpleStateCheckerTestBase.MyStateEntity[]
{
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2022-01-01", CultureInfo.InvariantCulture),
LastModificationTime = DateTime.Parse("2022-01-01", CultureInfo.InvariantCulture)
},
new SimpleStateCheckerTestBase.MyStateEntity()
{
CreationTime = DateTime.Parse("2020-01-01", CultureInfo.InvariantCulture)
}
};
myStateEntities[0].AddSimpleStateChecker(new MySimpleBatchStateChecker());
myStateEntities[1].AddSimpleStateChecker(new MySimpleStateChecker());
var result = await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities);
result.Count.ShouldBe(2);
result[myStateEntities[0]].ShouldBeTrue();
result[myStateEntities[1]].ShouldBeFalse();
myStateEntities[0].CheckCount.ShouldBe(0);
myStateEntities[0].GlobalCheckCount.ShouldBe(1);
myStateEntities[0].MultipleCheckCount.ShouldBe(1);
myStateEntities[0].MultipleGlobalCheckCount.ShouldBe(1);
myStateEntities[1].CheckCount.ShouldBe(0);
myStateEntities[1].GlobalCheckCount.ShouldBe(0);
myStateEntities[1].MultipleCheckCount.ShouldBe(0);
myStateEntities[1].MultipleGlobalCheckCount.ShouldBe(1);
}
}
}

@ -0,0 +1,105 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Xunit;
namespace Volo.Abp.SimpleStateChecking
{
public class SimpleStateChecker_Tests : SimpleStateCheckerTestBase
{
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpSimpleStateCheckerOptions<MyStateEntity>>(options =>
{
options.GlobalSimpleStateCheckers.Add<MyGlobalSimpleStateChecker>();
options.GlobalSimpleStateCheckers.Add<MyGlobalSimpleBatchStateChecker>();
});
base.AfterAddApplication(services);
}
[Fact]
public async Task State_Check_Should_Be_Works()
{
var myStateEntity = new MyStateEntity()
{
CreationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture),
LastModificationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture)
};
myStateEntity.AddSimpleStateChecker(new MySimpleStateChecker());
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntity)).ShouldBeTrue();
myStateEntity.CreationTime = DateTime.Parse("2001-01-01", CultureInfo.InvariantCulture);
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntity)).ShouldBeFalse();
}
[Fact]
public async Task Global_State_Check_Should_Be_Works()
{
var myStateEntity = new MyStateEntity()
{
CreationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture)
};
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntity)).ShouldBeFalse();
myStateEntity.LastModificationTime = DateTime.Parse("2001-01-01", CultureInfo.InvariantCulture);
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntity)).ShouldBeTrue();
}
[Fact]
public async Task Multiple_State_Check_Should_Be_Works()
{
var checker = new MySimpleBatchStateChecker();
var myStateEntities = new MyStateEntity[]
{
new MyStateEntity()
{
CreationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture),
LastModificationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture)
},
new MyStateEntity()
{
CreationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture),
LastModificationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture)
}
};
foreach (var myStateEntity in myStateEntities)
{
myStateEntity.AddSimpleStateChecker(checker);
}
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities)).ShouldAllBe(x => x.Value);
foreach (var myStateEntity in myStateEntities)
{
myStateEntity.CreationTime = DateTime.Parse("2001-01-01", CultureInfo.InvariantCulture);
}
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntities)).ShouldAllBe(x => !x.Value);
}
[Fact]
public async Task Multiple_Global_State_Check_Should_Be_Works()
{
var myStateEntity = new MyStateEntity()
{
CreationTime = DateTime.Parse("2021-01-01", CultureInfo.InvariantCulture)
};
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntity)).ShouldBeFalse();
myStateEntity.LastModificationTime = DateTime.Parse("2001-01-01", CultureInfo.InvariantCulture);
(await SimpleStateCheckerManager.IsEnabledAsync(myStateEntity)).ShouldBeTrue();
}
}
}

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Shouldly;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Security.Claims;
using Volo.Abp.Testing;
using Xunit;
@ -73,8 +74,8 @@ namespace Volo.Abp.UI.Navigation
var administration = context.Menu.GetAdministration();
administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management", url: "/admin/users", requiredPermissionName: "Administration.UserManagement"));
administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management", url: "/admin/roles", requiredPermissionName: "Administration.RoleManagement"));
administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management", url: "/admin/users").RequirePermissions("Administration.UserManagement"));
administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management", url: "/admin/roles").RequirePermissions("Administration.RoleManagement"));
return Task.CompletedTask;
}
@ -94,16 +95,16 @@ namespace Volo.Abp.UI.Navigation
return Task.CompletedTask;
}
context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard", url: "/dashboard", requiredPermissionName: "Dashboard"));
context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard", url: "/dashboard").RequirePermissions("Dashboard"));
var administration = context.Menu.GetAdministration();
administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard", requiredPermissionName: "Administration.DashboardSettings"));
administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard").RequirePermissions("Administration.DashboardSettings"));
administration.AddItem(
new ApplicationMenuItem("Administration.SubMenu1", "Sub menu 1", url: "/submenu1")
.AddItem(new ApplicationMenuItem("Administration.SubMenu1.1", "Sub menu 1.1", url: "/submenu1/submenu1_1", requiredPermissionName: "Administration.SubMenu1.1"))
.AddItem(new ApplicationMenuItem("Administration.SubMenu1.2", "Sub menu 1.2", url: "/submenu1/submenu1_2", requiredPermissionName: "Administration.SubMenu1.2"))
.AddItem(new ApplicationMenuItem("Administration.SubMenu1.1", "Sub menu 1.1", url: "/submenu1/submenu1_1").RequirePermissions("Administration.SubMenu1.1"))
.AddItem(new ApplicationMenuItem("Administration.SubMenu1.2", "Sub menu 1.2", url: "/submenu1/submenu1_2").RequirePermissions("Administration.SubMenu1.2"))
);
return Task.CompletedTask;

@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Volo.Abp.UI.Navigation;
using Volo.Abp.Authorization.Permissions;
using Volo.Blogging.Localization;
namespace Volo.Blogging.Admin
@ -18,9 +19,9 @@ namespace Volo.Blogging.Admin
{
var l = context.GetLocalizer<BloggingResource>();
var managementRootMenuItem = new ApplicationMenuItem("BlogManagement", l["Menu:BlogManagement"], requiredPermissionName: BloggingPermissions.Blogs.Management);
var managementRootMenuItem = new ApplicationMenuItem("BlogManagement", l["Menu:BlogManagement"]).RequirePermissions(BloggingPermissions.Blogs.Management);
managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Blogging/Admin/Blogs", requiredPermissionName: BloggingPermissions.Blogs.Management));
managementRootMenuItem.AddItem(new ApplicationMenuItem("BlogManagement.Blogs", l["Menu:Blogs"], "~/Blogging/Admin/Blogs").RequirePermissions(BloggingPermissions.Blogs.Management));
context.Menu.GetAdministration().AddItem(managementRootMenuItem);

@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.UI.Navigation;
using Volo.Abp.Authorization.Permissions;
using Volo.Docs.Localization;
namespace Volo.Docs.Admin.Navigation
@ -27,8 +28,8 @@ namespace Volo.Docs.Admin.Navigation
administrationMenu.AddItem(rootMenuItem);
rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Projects, l["Menu:ProjectManagement"], "~/Docs/Admin/Projects", requiredPermissionName: DocsAdminPermissions.Projects.Default));
rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Documents, l["Menu:DocumentManagement"], "~/Docs/Admin/Documents", requiredPermissionName: DocsAdminPermissions.Documents.Default));
rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Projects, l["Menu:ProjectManagement"], "~/Docs/Admin/Projects").RequirePermissions(DocsAdminPermissions.Projects.Default));
rootMenuItem.AddItem(new ApplicationMenuItem(DocsMenuNames.Documents, l["Menu:DocumentManagement"], "~/Docs/Admin/Documents").RequirePermissions(DocsAdminPermissions.Documents.Default));
return Task.CompletedTask;
}

@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Volo.Abp.Identity.Localization;
using Volo.Abp.UI.Navigation;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.Identity.Blazor
{
@ -24,15 +25,13 @@ namespace Volo.Abp.Identity.Blazor
identityMenuItem.AddItem(new ApplicationMenuItem(
IdentityMenuNames.Roles,
l["Roles"],
url: "~/identity/roles",
requiredPermissionName: IdentityPermissions.Roles.Default));
url: "~/identity/roles").RequirePermissions(IdentityPermissions.Roles.Default));
identityMenuItem.AddItem(new ApplicationMenuItem(
IdentityMenuNames.Users,
l["Users"],
url: "~/identity/users",
requiredPermissionName: IdentityPermissions.Users.Default));
url: "~/identity/users").RequirePermissions(IdentityPermissions.Users.Default));
return Task.CompletedTask;
}

@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.Identity.Localization;
using Volo.Abp.UI.Navigation;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.Identity.Web.Navigation
{
@ -19,8 +20,8 @@ namespace Volo.Abp.Identity.Web.Navigation
var l = context.GetLocalizer<IdentityResource>();
var identityMenuItem = new ApplicationMenuItem(IdentityMenuNames.GroupName, l["Menu:IdentityManagement"], icon: "fa fa-id-card-o");
identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "~/Identity/Roles", requiredPermissionName: IdentityPermissions.Roles.Default));
identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "~/Identity/Users", requiredPermissionName: IdentityPermissions.Users.Default));
identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Roles, l["Roles"], url: "~/Identity/Roles").RequirePermissions(IdentityPermissions.Roles.Default));
identityMenuItem.AddItem(new ApplicationMenuItem(IdentityMenuNames.Users, l["Users"], url: "~/Identity/Users").RequirePermissions( IdentityPermissions.Users.Default));
context.Menu.GetAdministration().AddItem(identityMenuItem);

@ -7,6 +7,7 @@ using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.MultiTenancy;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.PermissionManagement
{
@ -16,18 +17,18 @@ namespace Volo.Abp.PermissionManagement
protected PermissionManagementOptions Options { get; }
protected IPermissionManager PermissionManager { get; }
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
protected IPermissionStateManager PermissionStateManager { get; }
protected ISimpleStateCheckerManager<PermissionDefinition> SimpleStateCheckerManager { get; }
public PermissionAppService(
IPermissionManager permissionManager,
IPermissionDefinitionManager permissionDefinitionManager,
IOptions<PermissionManagementOptions> options,
IPermissionStateManager permissionStateManager)
ISimpleStateCheckerManager<PermissionDefinition> simpleStateCheckerManager)
{
Options = options.Value;
PermissionManager = permissionManager;
PermissionDefinitionManager = permissionDefinitionManager;
PermissionStateManager = permissionStateManager;
SimpleStateCheckerManager = simpleStateCheckerManager;
}
public virtual async Task<GetPermissionListResultDto> GetAsync(string providerName, string providerKey)
@ -58,7 +59,7 @@ namespace Volo.Abp.PermissionManagement
continue;
}
if (!await PermissionStateManager.IsEnabledAsync(permission))
if (!await SimpleStateCheckerManager.IsEnabledAsync(permission))
{
continue;
}

@ -9,6 +9,7 @@ using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.PermissionManagement
{
@ -18,7 +19,7 @@ namespace Volo.Abp.PermissionManagement
protected IPermissionDefinitionManager PermissionDefinitionManager { get; }
protected IPermissionStateManager PermissionStateManager { get; }
protected ISimpleStateCheckerManager<PermissionDefinition> SimpleStateCheckerManager { get; }
protected IGuidGenerator GuidGenerator { get; }
@ -34,7 +35,7 @@ namespace Volo.Abp.PermissionManagement
public PermissionManager(
IPermissionDefinitionManager permissionDefinitionManager,
IPermissionStateManager permissionStateManager,
ISimpleStateCheckerManager<PermissionDefinition> simpleStateCheckerManager,
IPermissionGrantRepository permissionGrantRepository,
IServiceProvider serviceProvider,
IGuidGenerator guidGenerator,
@ -45,7 +46,7 @@ namespace Volo.Abp.PermissionManagement
GuidGenerator = guidGenerator;
CurrentTenant = currentTenant;
Cache = cache;
PermissionStateManager = permissionStateManager;
SimpleStateCheckerManager = simpleStateCheckerManager;
PermissionGrantRepository = permissionGrantRepository;
PermissionDefinitionManager = permissionDefinitionManager;
Options = options.Value;
@ -80,7 +81,7 @@ namespace Volo.Abp.PermissionManagement
{
var permission = PermissionDefinitionManager.Get(permissionName);
if (!permission.IsEnabled || !await PermissionStateManager.IsEnabledAsync(permission))
if (!permission.IsEnabled || !await SimpleStateCheckerManager.IsEnabledAsync(permission))
{
//TODO: BusinessException
throw new ApplicationException($"The permission named '{permission.Name}' is disabled!");
@ -150,7 +151,7 @@ namespace Volo.Abp.PermissionManagement
return result;
}
if (!await PermissionStateManager.IsEnabledAsync(permission))
if (!await SimpleStateCheckerManager.IsEnabledAsync(permission))
{
return result;
}

@ -19,7 +19,7 @@ namespace Volo.Abp.PermissionManagement
testGroup.AddPermission("MyPermission4", multiTenancySide: MultiTenancySides.Host).WithProviders(UserPermissionValueProvider.ProviderName);
testGroup.AddPermission("MyPermission5").AddStateProviders(new TestRequireRolePermissionStateProvider("super-admin"));
testGroup.AddPermission("MyPermission5").SimpleStateCheckers.Add(new TestRequireRolePermissionStateProvider("super-admin"));
}
}
}

@ -4,10 +4,11 @@ using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Security.Claims;
using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.PermissionManagement
{
public class TestRequireRolePermissionStateProvider : IPermissionStateProvider
public class TestRequireRolePermissionStateProvider : ISimpleStateChecker<PermissionDefinition>
{
private readonly List<string> _allowRoles = new List<string>();
@ -16,7 +17,7 @@ namespace Volo.Abp.PermissionManagement
_allowRoles.AddRange(roles);
}
public Task<bool> IsEnabledAsync(PermissionStateContext context)
public Task<bool> IsEnabledAsync(SimpleStateCheckerContext<PermissionDefinition> context)
{
var currentPrincipalAccessor = context.ServiceProvider.GetRequiredService<ICurrentPrincipalAccessor>();
return Task.FromResult(currentPrincipalAccessor.Principal != null && _allowRoles.Any(role => currentPrincipalAccessor.Principal.IsInRole(role)));

@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Volo.Abp.TenantManagement.Localization;
using Volo.Abp.UI.Navigation;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.TenantManagement.Blazor.Navigation
{
@ -27,9 +28,8 @@ namespace Volo.Abp.TenantManagement.Blazor.Navigation
tenantManagementMenuItem.AddItem(new ApplicationMenuItem(
TenantManagementMenuNames.Tenants,
l["Tenants"],
url: "~/tenant-management/tenants",
requiredPermissionName: TenantManagementPermissions.Tenants.Default
));
url: "~/tenant-management/tenants"
).RequirePermissions(TenantManagementPermissions.Tenants.Default));
return Task.CompletedTask;
}

@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Volo.Abp.TenantManagement.Localization;
using Volo.Abp.UI.Navigation;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.TenantManagement.Web.Navigation
{
@ -23,7 +24,7 @@ namespace Volo.Abp.TenantManagement.Web.Navigation
var tenantManagementMenuItem = new ApplicationMenuItem(TenantManagementMenuNames.GroupName, l["Menu:TenantManagement"], icon: "fa fa-users");
administrationMenu.AddItem(tenantManagementMenuItem);
tenantManagementMenuItem.AddItem(new ApplicationMenuItem(TenantManagementMenuNames.Tenants, l["Tenants"], url: "~/TenantManagement/Tenants", requiredPermissionName: TenantManagementPermissions.Tenants.Default));
tenantManagementMenuItem.AddItem(new ApplicationMenuItem(TenantManagementMenuNames.Tenants, l["Tenants"], url: "~/TenantManagement/Tenants").RequirePermissions(TenantManagementPermissions.Tenants.Default));
return Task.CompletedTask;
}

Loading…
Cancel
Save