From ea590ec1d915f45fea1687c30048f0940b313741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 9 Aug 2022 17:30:48 +0300 Subject: [PATCH 01/70] Convert IPermissionDefinitionManager interface merthods to async --- .../AbpApplicationConfigurationAppService.cs | 2 +- .../IPermissionDefinitionManager.cs | 13 +++++----- .../AbpAuthorizationPolicyProvider.cs | 20 +++++++--------- .../Permissions/PermissionChecker.cs | 6 ++--- .../PermissionDefinitionManager.cs | 21 +++++++++------- .../Abp/Authorization/Authorization_Tests.cs | 4 ++-- .../PermissionStateProvider_Tests.cs | 4 ++-- .../PermissionAppService.cs | 2 +- .../PermissionDataSeedContributor.cs | 7 +++--- .../PermissionManagement/PermissionManager.cs | 24 +++++++++++++++---- .../PermissionManagement/PermissionStore.cs | 5 ++-- 11 files changed, 63 insertions(+), 45 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 528a04583d..fcef74990a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -171,7 +171,7 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp foreach (var policyName in policyNames) { - if (await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && _permissionDefinitionManager.GetOrNull(policyName) != null) + if (await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && _permissionDefinitionManager.GetOrNullAsync(policyName) != null) { abpPolicyNames.Add(policyName); } diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs index 553148671c..b4628a15bc 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs @@ -1,17 +1,18 @@ using System.Collections.Generic; +using System.Threading.Tasks; using JetBrains.Annotations; namespace Volo.Abp.Authorization.Permissions; public interface IPermissionDefinitionManager { - [NotNull] - PermissionDefinition Get([NotNull] string name); + [ItemNotNull] + Task GetAsync([NotNull] string name); - [CanBeNull] - PermissionDefinition GetOrNull([NotNull] string name); + [ItemCanBeNull] + Task GetOrNullAsync([NotNull] string name); - IReadOnlyList GetPermissions(); + Task> GetPermissionsAsync(); - IReadOnlyList GetGroups(); + Task> GetGroupsAsync(); } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs index 01037f3e96..fb37427c48 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationPolicyProvider.cs @@ -31,7 +31,7 @@ public class AbpAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider return policy; } - var permission = _permissionDefinitionManager.GetOrNull(policyName); + var permission = await _permissionDefinitionManager.GetOrNullAsync(policyName); if (permission != null) { //TODO: Optimize & Cache! @@ -43,16 +43,14 @@ public class AbpAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider return null; } - public Task> GetPoliciesNamesAsync() + public async Task> GetPoliciesNamesAsync() { - return Task.FromResult( - _options.GetPoliciesNames() - .Union( - _permissionDefinitionManager - .GetPermissions() - .Select(p => p.Name) - ) - .ToList() - ); + return _options.GetPoliciesNames() + .Union( + (await _permissionDefinitionManager + .GetPermissionsAsync()) + .Select(p => p.Name) + ) + .ToList(); } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs index fec8771afa..ed0fb2d8a9 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs @@ -43,8 +43,8 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency { Check.NotNull(name, nameof(name)); - var permission = PermissionDefinitionManager.Get(name); - + var permission = await PermissionDefinitionManager.GetAsync(name); + if (!permission.IsEnabled) { return false; @@ -108,7 +108,7 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency var permissionDefinitions = new List(); foreach (var name in names) { - var permission = PermissionDefinitionManager.Get(name); + var permission = await PermissionDefinitionManager.GetAsync(name); result.Result.Add(name, PermissionGrantResult.Undefined); diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index 7f4de3c767..a45442b02b 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -38,9 +39,9 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingle ); } - public virtual PermissionDefinition Get(string name) + public virtual async Task GetAsync(string name) { - var permission = GetOrNull(name); + var permission = await GetOrNullAsync(name); if (permission == null) { @@ -50,21 +51,25 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingle return permission; } - public virtual PermissionDefinition GetOrNull(string name) + public virtual Task GetOrNullAsync(string name) { Check.NotNull(name, nameof(name)); - return PermissionDefinitions.GetOrDefault(name); + return Task.FromResult(PermissionDefinitions.GetOrDefault(name)); } - public virtual IReadOnlyList GetPermissions() + public virtual Task> GetPermissionsAsync() { - return PermissionDefinitions.Values.ToImmutableList(); + return Task.FromResult>( + PermissionDefinitions.Values.ToImmutableList() + ); } - public IReadOnlyList GetGroups() + public Task> GetGroupsAsync() { - return PermissionGroupDefinitions.Values.ToImmutableList(); + return Task.FromResult>( + PermissionGroupDefinitions.Values.ToImmutableList() + ); } protected virtual Dictionary CreatePermissionDefinitions() diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs index 42f6d3ce4a..a32939fa53 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/Authorization_Tests.cs @@ -67,9 +67,9 @@ public class Authorization_Tests : AuthorizationTestBase } [Fact] - public void Should_Permission_Definition_GetGroup() + public async Task Should_Permission_Definition_GetGroup() { - _permissionDefinitionManager.GetGroups().Count.ShouldBe(1); + (await _permissionDefinitionManager.GetGroupsAsync()).Count.ShouldBe(1); } [Fact] diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs index b0be00fe01..23600bc261 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs @@ -29,7 +29,7 @@ public class SpecifyPermissionStateProvider : PermissionStateProvider_Tests [Fact] public async Task PermissionState_Test() { - var myPermission1 = PermissionDefinitionManager.Get("MyPermission1"); + var myPermission1 = await PermissionDefinitionManager.GetAsync("MyPermission1"); myPermission1.StateCheckers.ShouldContain(x => x.GetType() == typeof(TestRequireEditionPermissionSimpleStateChecker)); (await StateCheckerManager.IsEnabledAsync(myPermission1)).ShouldBeFalse(); @@ -54,7 +54,7 @@ public class GlobalPermissionStateProvider : PermissionStateProvider_Tests [Fact] public async Task Global_PermissionState_Test() { - var myPermission2 = PermissionDefinitionManager.Get("MyPermission2"); + var myPermission2 = await PermissionDefinitionManager.GetAsync("MyPermission2"); (await StateCheckerManager.IsEnabledAsync(myPermission2)).ShouldBeFalse(); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs index d7d7f28820..bc16824913 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs @@ -43,7 +43,7 @@ public class PermissionAppService : ApplicationService, IPermissionAppService var multiTenancySide = CurrentTenant.GetMultiTenancySide(); - foreach (var group in PermissionDefinitionManager.GetGroups()) + foreach (var group in await PermissionDefinitionManager.GetGroupsAsync()) { var groupDto = new PermissionGroupDto { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs index d0a98eb593..71570aafce 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDataSeedContributor.cs @@ -23,17 +23,16 @@ public class PermissionDataSeedContributor : IDataSeedContributor, ITransientDep CurrentTenant = currentTenant; } - public virtual Task SeedAsync(DataSeedContext context) + public virtual async Task SeedAsync(DataSeedContext context) { var multiTenancySide = CurrentTenant.GetMultiTenancySide(); - var permissionNames = PermissionDefinitionManager - .GetPermissions() + var permissionNames = (await PermissionDefinitionManager.GetPermissionsAsync()) .Where(p => p.MultiTenancySide.HasFlag(multiTenancySide)) .Where(p => !p.Providers.Any() || p.Providers.Contains(RolePermissionValueProvider.ProviderName)) .Select(p => p.Name) .ToArray(); - return PermissionDataSeeder.SeedAsync( + await PermissionDataSeeder.SeedAsync( RolePermissionValueProvider.ProviderName, "admin", permissionNames, diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs index 2e709c49c2..0e36316c5b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs @@ -62,18 +62,32 @@ public class PermissionManager : IPermissionManager, ISingletonDependency public virtual async Task GetAsync(string permissionName, string providerName, string providerKey) { - return await GetInternalAsync(PermissionDefinitionManager.Get(permissionName), providerName, providerKey); + return await GetInternalAsync( + await PermissionDefinitionManager.GetAsync(permissionName), + providerName, + providerKey + ); } public virtual async Task GetAsync(string[] permissionNames, string providerName, string providerKey) { - var permissionDefinitions = permissionNames.Select(x => PermissionDefinitionManager.Get(x)).ToArray(); - return await GetInternalAsync(permissionDefinitions, providerName, providerKey); + var permissionDefinitions = new PermissionDefinition[permissionNames.Length]; + + for (var i = 0; i < permissionNames.Length; i++) + { + permissionDefinitions[i] = await PermissionDefinitionManager.GetAsync(permissionNames[i]); + } + + return await GetInternalAsync( + permissionDefinitions, + providerName, + providerKey + ); } public virtual async Task> GetAllAsync(string providerName, string providerKey) { - var permissionDefinitions = PermissionDefinitionManager.GetPermissions().ToArray(); + var permissionDefinitions = (await PermissionDefinitionManager.GetPermissionsAsync()).ToArray(); var multiplePermissionWithGrantedProviders = await GetInternalAsync(permissionDefinitions, providerName, providerKey); @@ -83,7 +97,7 @@ public class PermissionManager : IPermissionManager, ISingletonDependency public virtual async Task SetAsync(string permissionName, string providerName, string providerKey, bool isGranted) { - var permission = PermissionDefinitionManager.Get(permissionName); + var permission = await PermissionDefinitionManager.GetAsync(permissionName); if (!permission.IsEnabled || !await SimpleStateCheckerManager.IsEnabledAsync(permission)) { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs index 5dd4e14ed0..6eed394a31 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs @@ -67,7 +67,7 @@ public class PermissionStore : IPermissionStore, ITransientDependency string currentName, PermissionGrantCacheItem currentCacheItem) { - var permissions = PermissionDefinitionManager.GetPermissions(); + var permissions = await PermissionDefinitionManager.GetPermissionsAsync(); Logger.LogDebug($"Getting all granted permissions from the repository for this provider name,key: {providerName},{providerKey}"); @@ -169,7 +169,8 @@ public class PermissionStore : IPermissionStore, ITransientDependency string providerKey, List notCacheKeys) { - var permissions = PermissionDefinitionManager.GetPermissions().Where(x => notCacheKeys.Any(k => GetPermissionNameFormCacheKeyOrNull(k) == x.Name)).ToList(); + var permissions = (await PermissionDefinitionManager.GetPermissionsAsync()) + .Where(x => notCacheKeys.Any(k => GetPermissionNameFormCacheKeyOrNull(k) == x.Name)).ToList(); Logger.LogDebug($"Getting not cache granted permissions from the repository for this provider name,key: {providerName},{providerKey}"); From 771155d5e70e4a841f9437dcfeb6df34107d1bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 9 Aug 2022 17:57:16 +0300 Subject: [PATCH 02/70] Extract class: StaticPermissionDefinitionStore --- .../IStaticPermissionDefinitionStore.cs | 13 ++ .../PermissionDefinitionManager.cs | 107 +-------------- .../StaticPermissionDefinitionStore.cs | 122 ++++++++++++++++++ 3 files changed, 142 insertions(+), 100 deletions(-) create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs new file mode 100644 index 0000000000..719412e4db --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions; + +public interface IStaticPermissionDefinitionStore +{ + Task GetOrNullAsync(string name); + + Task> GetPermissionsAsync(); + + Task> GetGroupsAsync(); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index a45442b02b..ea9871b65d 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs @@ -1,48 +1,21 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; +using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Authorization.Permissions; public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingletonDependency { - protected IDictionary PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value; - private readonly Lazy> _lazyPermissionGroupDefinitions; + private readonly IStaticPermissionDefinitionStore _staticStore; - protected IDictionary PermissionDefinitions => _lazyPermissionDefinitions.Value; - private readonly Lazy> _lazyPermissionDefinitions; - - protected AbpPermissionOptions Options { get; } - - private readonly IServiceProvider _serviceProvider; - - public PermissionDefinitionManager( - IOptions options, - IServiceProvider serviceProvider) + public PermissionDefinitionManager(IStaticPermissionDefinitionStore staticStore) { - _serviceProvider = serviceProvider; - Options = options.Value; - - _lazyPermissionDefinitions = new Lazy>( - CreatePermissionDefinitions, - isThreadSafe: true - ); - - _lazyPermissionGroupDefinitions = new Lazy>( - CreatePermissionGroupDefinitions, - isThreadSafe: true - ); + _staticStore = staticStore; } public virtual async Task GetAsync(string name) { var permission = await GetOrNullAsync(name); - if (permission == null) { throw new AbpException("Undefined permission: " + name); @@ -55,82 +28,16 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingle { Check.NotNull(name, nameof(name)); - return Task.FromResult(PermissionDefinitions.GetOrDefault(name)); + return _staticStore.GetOrNullAsync(name); } public virtual Task> GetPermissionsAsync() { - return Task.FromResult>( - PermissionDefinitions.Values.ToImmutableList() - ); + return _staticStore.GetPermissionsAsync(); } public Task> GetGroupsAsync() { - return Task.FromResult>( - PermissionGroupDefinitions.Values.ToImmutableList() - ); - } - - protected virtual Dictionary CreatePermissionDefinitions() - { - var permissions = new Dictionary(); - - foreach (var groupDefinition in PermissionGroupDefinitions.Values) - { - foreach (var permission in groupDefinition.Permissions) - { - AddPermissionToDictionaryRecursively(permissions, permission); - } - } - - return permissions; - } - - protected virtual void AddPermissionToDictionaryRecursively( - Dictionary permissions, - PermissionDefinition permission) - { - if (permissions.ContainsKey(permission.Name)) - { - throw new AbpException("Duplicate permission name: " + permission.Name); - } - - permissions[permission.Name] = permission; - - foreach (var child in permission.Children) - { - AddPermissionToDictionaryRecursively(permissions, child); - } - } - - protected virtual Dictionary CreatePermissionGroupDefinitions() - { - using (var scope = _serviceProvider.CreateScope()) - { - var context = new PermissionDefinitionContext(scope.ServiceProvider); - - var providers = Options - .DefinitionProviders - .Select(p => scope.ServiceProvider.GetRequiredService(p) as IPermissionDefinitionProvider) - .ToList(); - - foreach (var provider in providers) - { - provider.PreDefine(context); - } - - foreach (var provider in providers) - { - provider.Define(context); - } - - foreach (var provider in providers) - { - provider.PostDefine(context); - } - - return context.Groups; - } + return _staticStore.GetGroupsAsync(); } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs new file mode 100644 index 0000000000..ee4803d61e --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +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 StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, ISingletonDependency +{ + protected IDictionary PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value; + private readonly Lazy> _lazyPermissionGroupDefinitions; + + protected IDictionary PermissionDefinitions => _lazyPermissionDefinitions.Value; + private readonly Lazy> _lazyPermissionDefinitions; + + protected AbpPermissionOptions Options { get; } + + private readonly IServiceProvider _serviceProvider; + + public StaticPermissionDefinitionStore( + IServiceProvider serviceProvider, + IOptions options) + { + _serviceProvider = serviceProvider; + Options = options.Value; + + _lazyPermissionDefinitions = new Lazy>( + CreatePermissionDefinitions, + isThreadSafe: true + ); + + _lazyPermissionGroupDefinitions = new Lazy>( + CreatePermissionGroupDefinitions, + isThreadSafe: true + ); + } + + protected virtual Dictionary CreatePermissionDefinitions() + { + var permissions = new Dictionary(); + + foreach (var groupDefinition in PermissionGroupDefinitions.Values) + { + foreach (var permission in groupDefinition.Permissions) + { + AddPermissionToDictionaryRecursively(permissions, permission); + } + } + + return permissions; + } + + protected virtual void AddPermissionToDictionaryRecursively( + Dictionary permissions, + PermissionDefinition permission) + { + if (permissions.ContainsKey(permission.Name)) + { + throw new AbpException("Duplicate permission name: " + permission.Name); + } + + permissions[permission.Name] = permission; + + foreach (var child in permission.Children) + { + AddPermissionToDictionaryRecursively(permissions, child); + } + } + + protected virtual Dictionary CreatePermissionGroupDefinitions() + { + using (var scope = _serviceProvider.CreateScope()) + { + var context = new PermissionDefinitionContext(scope.ServiceProvider); + + var providers = Options + .DefinitionProviders + .Select(p => scope.ServiceProvider.GetRequiredService(p) as IPermissionDefinitionProvider) + .ToList(); + + foreach (var provider in providers) + { + provider.PreDefine(context); + } + + foreach (var provider in providers) + { + provider.Define(context); + } + + foreach (var provider in providers) + { + provider.PostDefine(context); + } + + return context.Groups; + } + } + + public Task GetOrNullAsync(string name) + { + return Task.FromResult(PermissionDefinitions.GetOrDefault(name)); + } + + public virtual Task> GetPermissionsAsync() + { + return Task.FromResult>( + PermissionDefinitions.Values.ToImmutableList() + ); + } + + public Task> GetGroupsAsync() + { + return Task.FromResult>( + PermissionGroupDefinitions.Values.ToImmutableList() + ); + } +} \ No newline at end of file From a82c9fc208a357c089f8e7d0cbe3a936d57d626f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 10:15:08 +0300 Subject: [PATCH 03/70] Introduce IDynamicPermissionDefinitionStore --- .../IDynamicPermissionDefinitionStore.cs | 13 ++++++ .../NullDynamicPermissionDefinitionStore.cs | 33 +++++++++++++++ .../PermissionDefinitionManager.cs | 41 +++++++++++++++---- 3 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs new file mode 100644 index 0000000000..ad74dae46b --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Volo.Abp.Authorization.Permissions; + +public interface IDynamicPermissionDefinitionStore +{ + Task GetOrNullAsync(string name); + + Task> GetPermissionsAsync(); + + Task> GetGroupsAsync(); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs new file mode 100644 index 0000000000..61e70b057c --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.Permissions; + +public class NullDynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ISingletonDependency +{ + private readonly static Task CachedPermissionResult = Task.FromResult((PermissionDefinition)null); + + private readonly static Task> CachedPermissionsResult = + Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); + + private readonly static Task> CachedGroupsResult = + Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); + + public Task GetOrNullAsync(string name) + { + return CachedPermissionResult; + } + + public Task> GetPermissionsAsync() + { + return CachedPermissionsResult; + } + + public Task> GetGroupsAsync() + { + return CachedGroupsResult; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index ea9871b65d..c8aba9371e 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; @@ -7,10 +9,14 @@ namespace Volo.Abp.Authorization.Permissions; public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingletonDependency { private readonly IStaticPermissionDefinitionStore _staticStore; + private readonly IDynamicPermissionDefinitionStore _dynamicStore; - public PermissionDefinitionManager(IStaticPermissionDefinitionStore staticStore) + public PermissionDefinitionManager( + IStaticPermissionDefinitionStore staticStore, + IDynamicPermissionDefinitionStore dynamicStore) { _staticStore = staticStore; + _dynamicStore = dynamicStore; } public virtual async Task GetAsync(string name) @@ -28,16 +34,37 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingle { Check.NotNull(name, nameof(name)); - return _staticStore.GetOrNullAsync(name); + return _staticStore.GetOrNullAsync(name) ?? + _dynamicStore.GetOrNullAsync(name); } - public virtual Task> GetPermissionsAsync() + public virtual async Task> GetPermissionsAsync() { - return _staticStore.GetPermissionsAsync(); + var staticPermissions = await _staticStore.GetPermissionsAsync(); + var staticPermissionNames = staticPermissions + .Select(p => p.Name) + .ToImmutableHashSet(); + + var dynamicPermissions = await _dynamicStore.GetPermissionsAsync(); + + /* We prefer static permissions over dynamics */ + return staticPermissions.Concat( + dynamicPermissions.Where(d => !staticPermissionNames.Contains(d.Name)) + ).ToImmutableList(); } - public Task> GetGroupsAsync() + public async Task> GetGroupsAsync() { - return _staticStore.GetGroupsAsync(); + var staticGroups = await _staticStore.GetGroupsAsync(); + var staticGroupNames = staticGroups + .Select(p => p.Name) + .ToImmutableHashSet(); + + var dynamicGroups = await _dynamicStore.GetGroupsAsync(); + + /* We prefer static groups over dynamics */ + return staticGroups.Concat( + dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name)) + ).ToImmutableList(); } -} +} \ No newline at end of file From 8b795f9828234a807a20f2b1ea02c48d45ea855e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 10:26:10 +0300 Subject: [PATCH 04/70] Allow to check permissions without defining them. --- .../Permissions/PermissionChecker.cs | 18 ++++++++++++++---- .../PermissionStateProvider_Tests.cs | 6 ++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs index ed0fb2d8a9..168eb3064b 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs @@ -43,7 +43,11 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency { Check.NotNull(name, nameof(name)); - var permission = await PermissionDefinitionManager.GetAsync(name); + var permission = await PermissionDefinitionManager.GetOrNullAsync(name); + if (permission == null) + { + return false; + } if (!permission.IsEnabled) { @@ -97,18 +101,24 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency { Check.NotNull(names, nameof(names)); - var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? CurrentTenant.GetMultiTenancySide(); - var result = new MultiplePermissionGrantResult(); if (!names.Any()) { return result; } + var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? + CurrentTenant.GetMultiTenancySide(); + var permissionDefinitions = new List(); foreach (var name in names) { - var permission = await PermissionDefinitionManager.GetAsync(name); + var permission = await PermissionDefinitionManager.GetOrNullAsync(name); + if (permission == null) + { + result.Result.Add(name, PermissionGrantResult.Prohibited); + continue; + } result.Result.Add(name, PermissionGrantResult.Undefined); diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs index 23600bc261..50805d4b58 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionStateProvider_Tests.cs @@ -29,7 +29,8 @@ public class SpecifyPermissionStateProvider : PermissionStateProvider_Tests [Fact] public async Task PermissionState_Test() { - var myPermission1 = await PermissionDefinitionManager.GetAsync("MyPermission1"); + var myPermission1 = await PermissionDefinitionManager.GetOrNullAsync("MyPermission1"); + myPermission1.ShouldNotBeNull(); myPermission1.StateCheckers.ShouldContain(x => x.GetType() == typeof(TestRequireEditionPermissionSimpleStateChecker)); (await StateCheckerManager.IsEnabledAsync(myPermission1)).ShouldBeFalse(); @@ -54,7 +55,8 @@ public class GlobalPermissionStateProvider : PermissionStateProvider_Tests [Fact] public async Task Global_PermissionState_Test() { - var myPermission2 = await PermissionDefinitionManager.GetAsync("MyPermission2"); + var myPermission2 = await PermissionDefinitionManager.GetOrNullAsync("MyPermission2"); + myPermission2.ShouldNotBeNull(); (await StateCheckerManager.IsEnabledAsync(myPermission2)).ShouldBeFalse(); From 8369764170bbcd487e0c15624f895fb64253f08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 10:58:02 +0300 Subject: [PATCH 05/70] Support undefined permissions in PermissionManager. --- .../PermissionManagement/PermissionManager.cs | 68 ++++++++++++++++--- .../PermissionChecker_Basic_Tests.cs | 6 +- .../PermissionManager_Tests.cs | 16 ++--- 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs index 0e36316c5b..b664e5c92d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs @@ -62,27 +62,57 @@ public class PermissionManager : IPermissionManager, ISingletonDependency public virtual async Task GetAsync(string permissionName, string providerName, string providerKey) { + var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName); + if (permission == null) + { + return new PermissionWithGrantedProviders(permissionName, false); + } + return await GetInternalAsync( - await PermissionDefinitionManager.GetAsync(permissionName), + permission, providerName, providerKey ); } - public virtual async Task GetAsync(string[] permissionNames, string providerName, string providerKey) + public virtual async Task GetAsync( + string[] permissionNames, + string providerName, + string providerKey) { - var permissionDefinitions = new PermissionDefinition[permissionNames.Length]; + var permissions = new List(); + var undefinedPermissions = new List(); + + foreach (var permissionName in permissionNames) + { + var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName); + if (permission != null) + { + permissions.Add(permission); + } + else + { + undefinedPermissions.Add(permissionName); + } + } - for (var i = 0; i < permissionNames.Length; i++) + if (!permissions.Any()) { - permissionDefinitions[i] = await PermissionDefinitionManager.GetAsync(permissionNames[i]); + return new MultiplePermissionWithGrantedProviders(undefinedPermissions.ToArray()); } - return await GetInternalAsync( - permissionDefinitions, + var result = await GetInternalAsync( + permissions.ToArray(), providerName, providerKey ); + + foreach (var undefinedPermission in undefinedPermissions) + { + result.Result.Add(new PermissionWithGrantedProviders(undefinedPermission, false)); + } + + return result; } public virtual async Task> GetAllAsync(string providerName, string providerKey) @@ -97,7 +127,13 @@ public class PermissionManager : IPermissionManager, ISingletonDependency public virtual async Task SetAsync(string permissionName, string providerName, string providerKey, bool isGranted) { - var permission = await PermissionDefinitionManager.GetAsync(permissionName); + var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName); + if (permission == null) + { + /* Silently ignore undefined permissions, + maybe they were removed from dynamic permission definition store */ + return; + } if (!permission.IsEnabled || !await SimpleStateCheckerManager.IsEnabledAsync(permission)) { @@ -160,14 +196,24 @@ public class PermissionManager : IPermissionManager, ISingletonDependency } } - protected virtual async Task GetInternalAsync(PermissionDefinition permission, string providerName, string providerKey) + protected virtual async Task GetInternalAsync( + PermissionDefinition permission, + string providerName, + string providerKey) { - var multiplePermissionWithGrantedProviders = await GetInternalAsync(new PermissionDefinition[] { permission }, providerName, providerKey); + var multiplePermissionWithGrantedProviders = await GetInternalAsync( + new[] { permission }, + providerName, + providerKey + ); return multiplePermissionWithGrantedProviders.Result.First(); } - protected virtual async Task GetInternalAsync(PermissionDefinition[] permissions, string providerName, string providerKey) + protected virtual async Task GetInternalAsync( + PermissionDefinition[] permissions, + string providerName, + string providerKey) { var permissionNames = permissions.Select(x => x.Name).ToArray(); var multiplePermissionWithGrantedProviders = new MultiplePermissionWithGrantedProviders(permissionNames); diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs index aa9e7ecca9..78ab5d0af9 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionChecker_Basic_Tests.cs @@ -15,11 +15,9 @@ public class PermissionChecker_Basic_Tests : PermissionTestBase } [Fact] - public async Task Should_Throw_Exception_If_Permission_Is_Not_Defined() + public async Task Should_Return_Prohibited_If_Permission_Is_Not_Defined() { - await Assert.ThrowsAsync(async () => - await _permissionChecker.IsGrantedAsync("UndefinedPermissionName") - ); + (await _permissionChecker.IsGrantedAsync("UndefinedPermissionName")).ShouldBeFalse(); } [Fact] diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs index 06e245046c..1f771bdb3b 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionManager_Tests.cs @@ -72,12 +72,12 @@ public class PermissionManager_Tests : PermissionTestBase } [Fact] - public async Task Get_Should_Exception_When_Permission_Undefined() + public async Task Get_Should_Return_Not_Granted_When_Permission_Undefined() { - await Assert.ThrowsAsync(async () => await _permissionManager.GetAsync( - "MyPermission1NotExist", - "Test", - "Test")); + var result = await _permissionManager.GetAsync("MyPermission1NotExist", "Test", "Test"); + result.Name.ShouldBe("MyPermission1NotExist"); + result.Providers.ShouldBeEmpty(); + result.IsGranted.ShouldBeFalse(); } [Fact] @@ -126,13 +126,13 @@ public class PermissionManager_Tests : PermissionTestBase } [Fact] - public async Task Set_Should_Exception_When_Permission_Undefined() + public async Task Set_Should_Silently_Ignore_When_Permission_Undefined() { - await Assert.ThrowsAsync(async () => await _permissionManager.SetAsync( + await _permissionManager.SetAsync( "MyPermission1NotExist", "Test", "Test", - true)); + true); } [Fact] From c62af908a4d7bb373a84bf8766fe858b7a1ec160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 13:47:03 +0300 Subject: [PATCH 06/70] Introduce IAbpApplication.ApplicationName --- .../ServiceCollectionApplicationExtensions.cs | 6 ++++++ .../Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs | 4 ++++ .../Volo/Abp/AbpApplicationCreationOptions.cs | 3 +++ .../AbpApplicationWithInternalServiceProvider.cs | 2 +- .../src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs | 7 +++++++ .../Volo/Abp/AbpApplication_Initialize_Tests.cs | 15 +++++++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs index ce4af2befa..204d582ca5 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs @@ -39,4 +39,10 @@ public static class ServiceCollectionApplicationExtensions { return await AbpApplicationFactory.CreateAsync(startupModuleType, services, optionsAction); } + + [CanBeNull] + public static string GetApplicationName(this IServiceCollection services) + { + return services.GetSingletonInstance().ApplicationName; + } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs index 741f6f0586..e24403d0e3 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs @@ -23,6 +23,8 @@ public abstract class AbpApplicationBase : IAbpApplication public IServiceCollection Services { get; } public IReadOnlyList Modules { get; } + + public string ApplicationName { get; } private bool _configuredServices; @@ -41,6 +43,8 @@ public abstract class AbpApplicationBase : IAbpApplication var options = new AbpApplicationCreationOptions(services); optionsAction?.Invoke(options); + + ApplicationName = options.ApplicationName; services.AddSingleton(this); services.AddSingleton(this); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs index d18e43275b..24a1bf8ee6 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationCreationOptions.cs @@ -20,6 +20,9 @@ public class AbpApplicationCreationOptions public AbpConfigurationBuilderOptions Configuration { get; } public bool SkipConfigureServices { get; set; } + + [CanBeNull] + public string ApplicationName { get; set; } public AbpApplicationCreationOptions([NotNull] IServiceCollection services) { diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs index 245ce6fb06..5f09157fcc 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationWithInternalServiceProvider.cs @@ -60,6 +60,6 @@ internal class AbpApplicationWithInternalServiceProvider : AbpApplicationBase, I public override void Dispose() { base.Dispose(); - ServiceScope.Dispose(); + ServiceScope?.Dispose(); } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs index 2fb66b735f..e132df5a59 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs @@ -24,6 +24,13 @@ public interface IAbpApplication : IModuleContainer, IDisposable /// IServiceProvider ServiceProvider { get; } + /// + /// Name of the application. + /// This is useful for systems with multiple applications, to distinguish + /// resources of the applications located together. + /// + string ApplicationName { get; } + /// /// Calls the Pre/Post/ConfigureServicesAsync methods of the modules. /// If you use this method, you must have set the diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs index f69d94ce61..4ce2bf1d36 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs @@ -142,4 +142,19 @@ public class AbpApplication_Initialize_Tests plugInModule.OnApplicationShutdownIsCalled.ShouldBeTrue(); } } + + [Fact] + public void Should_Set_And_Get_ApplicationName() + { + const string applicationName = "MyApplication"; + + using (var application = AbpApplicationFactory.Create(options => + { + options.ApplicationName = applicationName; + })) + { + application.ApplicationName.ShouldBe(applicationName); + application.Services.GetApplicationName().ShouldBe(applicationName); + } + } } From ba8ed35deb27c23881636eb497f4f6e7713b8815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 13:47:20 +0300 Subject: [PATCH 07/70] PermissionDefinitionManager can be transient. --- .../Authorization/Permissions/PermissionDefinitionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index c8aba9371e..27c963fb5d 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs @@ -6,7 +6,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Authorization.Permissions; -public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingletonDependency +public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransientDependency { private readonly IStaticPermissionDefinitionStore _staticStore; private readonly IDynamicPermissionDefinitionStore _dynamicStore; From c9df1208b72f5de4c8d25948b86a7291057dbe78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 14:47:56 +0300 Subject: [PATCH 08/70] Remove MultiTenancySides from PermissionGroupDefinition. This is a breaking change and I will create a separate issue to explain it. --- .../Permissions/IPermissionDefinitionContext.cs | 3 +-- .../Permissions/PermissionDefinitionContext.cs | 5 ++--- .../Permissions/PermissionGroupDefinition.cs | 12 ++---------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs index 6d1f9a31fd..411b030b6a 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs @@ -37,8 +37,7 @@ public interface IPermissionDefinitionContext /// PermissionGroupDefinition AddGroup( [NotNull] string name, - ILocalizableString displayName = null, - MultiTenancySides multiTenancySide = MultiTenancySides.Both); + ILocalizableString displayName = null); /// /// Tries to remove a permission group. diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs index 7a10fe4b5e..5b5543e868 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs @@ -20,8 +20,7 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext public virtual PermissionGroupDefinition AddGroup( string name, - ILocalizableString displayName = null, - MultiTenancySides multiTenancySide = MultiTenancySides.Both) + ILocalizableString displayName = null) { Check.NotNull(name, nameof(name)); @@ -30,7 +29,7 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext throw new AbpException($"There is already an existing permission group with name: {name}"); } - return Groups[name] = new PermissionGroupDefinition(name, displayName, multiTenancySide); + return Groups[name] = new PermissionGroupDefinition(name, displayName); } [NotNull] diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs index d2efedc0d9..6c3edd7f12 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs @@ -6,7 +6,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.Authorization.Permissions; -public class PermissionGroupDefinition //TODO: Consider to make possible a group have sub groups +public class PermissionGroupDefinition { /// /// Unique name of the group. @@ -21,12 +21,6 @@ public class PermissionGroupDefinition //TODO: Consider to make possible a group } private ILocalizableString _displayName; - /// - /// MultiTenancy side. - /// Default: - /// - public MultiTenancySides MultiTenancySide { get; set; } - public IReadOnlyList Permissions => _permissions.ToImmutableList(); private readonly List _permissions; @@ -45,12 +39,10 @@ public class PermissionGroupDefinition //TODO: Consider to make possible a group protected internal PermissionGroupDefinition( string name, - ILocalizableString displayName = null, - MultiTenancySides multiTenancySide = MultiTenancySides.Both) + ILocalizableString displayName = null) { Name = name; DisplayName = displayName ?? new FixedLocalizableString(Name); - MultiTenancySide = multiTenancySide; Properties = new Dictionary(); _permissions = new List(); From 0602d99bf759844d93fa84d3fdcd0b69f1255919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 15:05:12 +0300 Subject: [PATCH 09/70] Define PermissionDefinitionRecord and PermissionGroupDefinitionRecord --- .../PermissionDefinitionRecord.cs | 51 +++++++++++++++++++ .../PermissionGroupDefinitionRecord.cs | 20 ++++++++ 2 files changed, 71 insertions(+) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs new file mode 100644 index 0000000000..de32b4e30d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -0,0 +1,51 @@ +using System; +using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraProperties +{ + public string GroupName { get; set; } + + public string Name { get; set; } + + public string ParentName { get; set; } + + public bool IsEnabled { get; set; } + + public MultiTenancySides MultiTenancySide { get; set; } + + /// + /// Comma separated list of provider names. + /// + public string Providers { get; set; } + + public string DisplayName { get; set; } + + /// + /// A JSON array containing feature checkers data. + /// + /// Example: + /// [ + /// { + /// "type": "RequireFeatures", + /// "featureNames": [ "FeatureA", "FeatureB" ] + /// }, + /// { + /// "type": "RequireGlobalFeatures", + /// "featureNames": [ "GlobalFeatureA", "GlobalFeatureB" ] + /// } + /// ] + /// + public string StateCheckers { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; protected set; } + + public PermissionDefinitionRecord() + { + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs new file mode 100644 index 0000000000..6addd6c8a8 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs @@ -0,0 +1,20 @@ +using System; +using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionGroupDefinitionRecord : BasicAggregateRoot, IHasExtraProperties +{ + public string Name { get; set; } + + public string DisplayName { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; protected set; } + + public PermissionGroupDefinitionRecord() + { + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } +} \ No newline at end of file From 1d331b6fc04a9732034a14416367cf6e67f42521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 15:19:01 +0300 Subject: [PATCH 10/70] Create entity ctors. --- .../PermissionDefinitionRecordConsts.cs | 11 ++++++++ .../PermissionGroupDefinitionRecordConsts.cs | 11 ++++++++ .../PermissionDefinitionRecord.cs | 25 +++++++++++++++++++ .../PermissionGroupDefinitionRecord.cs | 13 ++++++++++ 4 files changed, 60 insertions(+) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecordConsts.cs diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs new file mode 100644 index 0000000000..0f7aa20468 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionRecordConsts +{ + /// + /// Default value: 128 + /// + public static int MaxNameLength { get; set; } = 128; + + public static int MaxDisplayNameLength { get; set; } = 256; +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecordConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecordConsts.cs new file mode 100644 index 0000000000..fb26c075b8 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecordConsts.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp.PermissionManagement; + +public class PermissionGroupDefinitionRecordConsts +{ + /// + /// Default value: 128 + /// + public static int MaxNameLength { get; set; } = 128; + + public static int MaxDisplayNameLength { get; set; } = 256; +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs index de32b4e30d..70d00cc6d6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -48,4 +48,29 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro ExtraProperties = new ExtraPropertyDictionary(); this.SetDefaultsForExtraProperties(); } + + public PermissionDefinitionRecord( + Guid id, + string groupName, + string name, + string parentName, + string displayName, + bool isEnabled = true, + MultiTenancySides multiTenancySide = MultiTenancySides.Both, + string providers = null, + string stateCheckers = null) + : base(id) + { + GroupName = Check.NotNullOrWhiteSpace(groupName, nameof(groupName), PermissionGroupDefinitionRecordConsts.MaxNameLength); + Name = Check.NotNullOrWhiteSpace(name, nameof(name), PermissionDefinitionRecordConsts.MaxNameLength); + ParentName = Check.NotNullOrWhiteSpace(parentName, nameof(parentName), PermissionDefinitionRecordConsts.MaxNameLength); + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), PermissionDefinitionRecordConsts.MaxDisplayNameLength); + IsEnabled = isEnabled; + MultiTenancySide = multiTenancySide; + Providers = providers; + StateCheckers = stateCheckers; + + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs index 6addd6c8a8..ff0c817ad2 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs @@ -17,4 +17,17 @@ public class PermissionGroupDefinitionRecord : BasicAggregateRoot, IHasExt ExtraProperties = new ExtraPropertyDictionary(); this.SetDefaultsForExtraProperties(); } + + public PermissionGroupDefinitionRecord( + Guid id, + string name, + string displayName) + : base(id) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name), PermissionGroupDefinitionRecordConsts.MaxNameLength); + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), PermissionGroupDefinitionRecordConsts.MaxDisplayNameLength);; + + ExtraProperties = new ExtraPropertyDictionary(); + this.SetDefaultsForExtraProperties(); + } } \ No newline at end of file From 0037ff28343b8abb8464b96c9cf392f6288f25ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 16:06:13 +0300 Subject: [PATCH 11/70] Change MultiTenancySides to byte for storage optimization when we want to store that type of data. --- .../Volo/Abp/MultiTenancy/MultiTenancySides.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs index bf094c6bc3..0b848554bb 100644 --- a/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs +++ b/framework/src/Volo.Abp.MultiTenancy/Volo/Abp/MultiTenancy/MultiTenancySides.cs @@ -6,7 +6,7 @@ namespace Volo.Abp.MultiTenancy; /// Represents sides in a multi tenancy application. /// [Flags] -public enum MultiTenancySides +public enum MultiTenancySides : byte { /// /// Tenant side. From b45d656f356a96059f123fbf35b3c6aaaf1652ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 16:07:04 +0300 Subject: [PATCH 12/70] Database mappings for permission entities. --- .../PermissionDefinitionRecordConsts.cs | 4 ++ .../PermissionGrantConsts.cs | 5 --- .../PermissionDefinitionRecord.cs | 18 ++------- ...nagementDbContextModelBuilderExtensions.cs | 38 ++++++++++++++++++- .../IPermissionManagementDbContext.cs | 4 ++ .../PermissionManagementDbContext.cs | 2 + ...ssionManagementMongoDbContextExtensions.cs | 10 +++++ .../IPermissionManagementMongoDbContext.cs | 4 ++ .../PermissionManagementMongoDbContext.cs | 2 + 9 files changed, 65 insertions(+), 22 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs index 0f7aa20468..93b1b465c6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs @@ -8,4 +8,8 @@ public class PermissionDefinitionRecordConsts public static int MaxNameLength { get; set; } = 128; public static int MaxDisplayNameLength { get; set; } = 256; + + public static int MaxProvidersLength { get; set; } = 128; + + public static int MaxStateCheckersLength { get; set; } = 256; } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs index 38a17340c5..630f5dc72e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionGrantConsts.cs @@ -2,11 +2,6 @@ public static class PermissionGrantConsts { - /// - /// Default value: 128 - /// - public static int MaxNameLength { get; set; } = 128; - /// /// Default value: 64 /// diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs index 70d00cc6d6..ec2e35136d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -13,6 +13,8 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro public string ParentName { get; set; } + public string DisplayName { get; set; } + public bool IsEnabled { get; set; } public MultiTenancySides MultiTenancySide { get; set; } @@ -22,22 +24,8 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro /// public string Providers { get; set; } - public string DisplayName { get; set; } - /// - /// A JSON array containing feature checkers data. - /// - /// Example: - /// [ - /// { - /// "type": "RequireFeatures", - /// "featureNames": [ "FeatureA", "FeatureB" ] - /// }, - /// { - /// "type": "RequireGlobalFeatures", - /// "featureNames": [ "GlobalFeatureA", "GlobalFeatureB" ] - /// } - /// ] + /// Serialized string to store info about the state checkers. /// public string StateCheckers { get; set; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs index bf9aa570a7..d8b3dd4362 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.EntityFrameworkCore.Modeling; namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; @@ -17,11 +18,44 @@ public static class AbpPermissionManagementDbContextModelBuilderExtensions b.ConfigureByConvention(); - b.Property(x => x.Name).HasMaxLength(PermissionGrantConsts.MaxNameLength).IsRequired(); + b.Property(x => x.Name).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength).IsRequired(); b.Property(x => x.ProviderName).HasMaxLength(PermissionGrantConsts.MaxProviderNameLength).IsRequired(); b.Property(x => x.ProviderKey).HasMaxLength(PermissionGrantConsts.MaxProviderKeyLength).IsRequired(); - b.HasIndex(x => new { x.TenantId, x.Name, x.ProviderName, x.ProviderKey }).IsUnique(true); + b.HasIndex(x => new { x.TenantId, x.Name, x.ProviderName, x.ProviderKey }).IsUnique(); + + b.ApplyObjectExtensionMappings(); + }); + + builder.Entity(b => + { + b.ToTable(AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGroups", AbpPermissionManagementDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.Property(x => x.Name).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.DisplayName).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxDisplayNameLength).IsRequired(); + + b.HasIndex(x => new { x.Name }).IsUnique(); + + b.ApplyObjectExtensionMappings(); + }); + + builder.Entity(b => + { + b.ToTable(AbpPermissionManagementDbProperties.DbTablePrefix + "Permissions", AbpPermissionManagementDbProperties.DbSchema); + + b.ConfigureByConvention(); + + b.Property(x => x.GroupName).HasMaxLength(PermissionGroupDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.Name).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength).IsRequired(); + b.Property(x => x.ParentName).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength); + b.Property(x => x.DisplayName).HasMaxLength(PermissionDefinitionRecordConsts.MaxDisplayNameLength).IsRequired(); + b.Property(x => x.Providers).HasMaxLength(PermissionDefinitionRecordConsts.MaxProvidersLength).IsRequired(); + b.Property(x => x.StateCheckers).HasMaxLength(PermissionDefinitionRecordConsts.MaxStateCheckersLength).IsRequired(); + + b.HasIndex(x => new { x.Name }).IsUnique(); + b.HasIndex(x => new { x.GroupName }); b.ApplyObjectExtensionMappings(); }); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs index 174ba1762a..c294c1b248 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/IPermissionManagementDbContext.cs @@ -7,5 +7,9 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public interface IPermissionManagementDbContext : IEfCoreDbContext { + DbSet PermissionGroups { get; } + + DbSet Permissions { get; } + DbSet PermissionGrants { get; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs index f1183eec16..fe143fa8ae 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/PermissionManagementDbContext.cs @@ -7,6 +7,8 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public class PermissionManagementDbContext : AbpDbContext, IPermissionManagementDbContext { + public DbSet PermissionGroups { get; set; } + public DbSet Permissions { get; set; } public DbSet PermissionGrants { get; set; } public PermissionManagementDbContext(DbContextOptions options) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs index a3d1461e58..9c7c90af58 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbContextExtensions.cs @@ -9,6 +9,16 @@ public static class AbpPermissionManagementMongoDbContextExtensions { Check.NotNull(builder, nameof(builder)); + builder.Entity(b => + { + b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGroups"; + }); + + builder.Entity(b => + { + b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "Permissions"; + }); + builder.Entity(b => { b.CollectionName = AbpPermissionManagementDbProperties.DbTablePrefix + "PermissionGrants"; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs index 0826003628..98015484fb 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/IPermissionManagementMongoDbContext.cs @@ -7,5 +7,9 @@ namespace Volo.Abp.PermissionManagement.MongoDB; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public interface IPermissionManagementMongoDbContext : IAbpMongoDbContext { + IMongoCollection PermissionGroups { get; } + + IMongoCollection Permissions { get; } + IMongoCollection PermissionGrants { get; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs index e8ef18f162..c62db52c11 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/PermissionManagementMongoDbContext.cs @@ -7,6 +7,8 @@ namespace Volo.Abp.PermissionManagement.MongoDB; [ConnectionStringName(AbpPermissionManagementDbProperties.ConnectionStringName)] public class PermissionManagementMongoDbContext : AbpMongoDbContext, IPermissionManagementMongoDbContext { + public IMongoCollection PermissionGroups => Collection(); + public IMongoCollection Permissions => Collection(); public IMongoCollection PermissionGrants => Collection(); protected override void CreateModel(IMongoModelBuilder modelBuilder) From 7624bc6ee3c215074e609c66393d9b36f72bf8cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 16:12:16 +0300 Subject: [PATCH 13/70] Implemented ef core repositories for permission objects --- .../IPermissionDefinitionRecordRepository.cs | 9 +++++++++ ...IPermissionGroupDefinitionRecordRepository.cs | 9 +++++++++ ...missionManagementEntityFrameworkCoreModule.cs | 2 ++ ...EfCorePermissionDefinitionRecordRepository.cs | 16 ++++++++++++++++ .../EfCorePermissionGrantRepository.cs | 3 ++- ...ePermissionGroupDefinitionRecordRepository.cs | 16 ++++++++++++++++ .../MongoDb/MongoPermissionGrantRepository.cs | 4 +++- 7 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGroupDefinitionRecordRepository.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGroupDefinitionRecordRepository.cs diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..c333db97d5 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.PermissionManagement; + +public interface IPermissionDefinitionRecordRepository : IBasicRepository +{ + +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGroupDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGroupDefinitionRecordRepository.cs new file mode 100644 index 0000000000..984adbe72d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGroupDefinitionRecordRepository.cs @@ -0,0 +1,9 @@ +using System; +using Volo.Abp.Domain.Repositories; + +namespace Volo.Abp.PermissionManagement; + +public interface IPermissionGroupDefinitionRecordRepository : IBasicRepository +{ + +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs index 6d7451c5e9..ebcc8527c1 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementEntityFrameworkCoreModule.cs @@ -14,6 +14,8 @@ public class AbpPermissionManagementEntityFrameworkCoreModule : AbpModule { options.AddDefaultRepositories(); + options.AddRepository(); + options.AddRepository(); options.AddRepository(); }); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..0aa44d7b98 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; + +public class EfCorePermissionDefinitionRecordRepository : + EfCoreRepository, + IPermissionDefinitionRecordRepository +{ + public EfCorePermissionDefinitionRecordRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs index 6345f69735..a080d39d87 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs @@ -9,7 +9,8 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; -public class EfCorePermissionGrantRepository : EfCoreRepository, +public class EfCorePermissionGrantRepository : + EfCoreRepository, IPermissionGrantRepository { public EfCorePermissionGrantRepository(IDbContextProvider dbContextProvider) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGroupDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGroupDefinitionRecordRepository.cs new file mode 100644 index 0000000000..923d238761 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGroupDefinitionRecordRepository.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; + +namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; + +public class EfCorePermissionGroupDefinitionRecordRepository : + EfCoreRepository, + IPermissionGroupDefinitionRecordRepository +{ + public EfCorePermissionGroupDefinitionRecordRepository( + IDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs index 908f258a47..aa7694b7d5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs @@ -10,7 +10,9 @@ using Volo.Abp.MongoDB; namespace Volo.Abp.PermissionManagement.MongoDB; -public class MongoPermissionGrantRepository : MongoDbRepository, IPermissionGrantRepository +public class MongoPermissionGrantRepository : + MongoDbRepository, + IPermissionGrantRepository { public MongoPermissionGrantRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) From 556667e7f0af6a027e934e1bbddb21b10b971d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 16:20:13 +0300 Subject: [PATCH 14/70] implemented mongo repos for permission entities. --- .../AbpPermissionManagementMongoDbModule.cs | 2 ++ .../MongoPermissionDefinitionRecordRepository.cs | 16 ++++++++++++++++ ...oPermissionGroupDefinitionRecordRepository.cs | 16 ++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGroupDefinitionRecordRepository.cs diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs index b62d651bf1..80831660f8 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/AbpPermissionManagementMongoDbModule.cs @@ -16,6 +16,8 @@ public class AbpPermissionManagementMongoDbModule : AbpModule { options.AddDefaultRepositories(); + options.AddRepository(); + options.AddRepository(); options.AddRepository(); }); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..5b2ade05e4 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.PermissionManagement.MongoDB; + +public class MongoPermissionDefinitionRecordRepository : + MongoDbRepository, + IPermissionDefinitionRecordRepository +{ + public MongoPermissionDefinitionRecordRepository( + IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGroupDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGroupDefinitionRecordRepository.cs new file mode 100644 index 0000000000..0b6b5550b9 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGroupDefinitionRecordRepository.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.Domain.Repositories.MongoDB; +using Volo.Abp.MongoDB; + +namespace Volo.Abp.PermissionManagement.MongoDB; + +public class MongoPermissionGroupDefinitionRecordRepository : + MongoDbRepository, + IPermissionGroupDefinitionRecordRepository +{ + public MongoPermissionGroupDefinitionRecordRepository( + IMongoDbContextProvider dbContextProvider) + : base(dbContextProvider) + { + } +} \ No newline at end of file From 4014a60dfb49e05e99e8679838e6b7ee1e4575eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 17:18:59 +0300 Subject: [PATCH 15/70] Introduce IRootServiceProviderAccessor --- .../IRootServiceProviderAccessor.cs | 12 ++++++++++++ .../RootServiceProviderAccessor.cs | 14 ++++++++++++++ .../Volo/Abp/AbpApplication_Initialize_Tests.cs | 16 ++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs new file mode 100644 index 0000000000..cb22e45287 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs @@ -0,0 +1,12 @@ +namespace Volo.Abp.DependencyInjection; + +/// +/// Gets the root service provider of the application. +/// Be careful to use the root service provider since there is no way +/// to release/dispose objects resolved from the root service provider. +/// So, always create a new scope if you need to resolve any service. +/// +public interface IRootServiceProviderAccessor : IServiceProviderAccessor +{ + +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs new file mode 100644 index 0000000000..1f0639be12 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Abp.DependencyInjection; + +[ExposeServices(typeof(IRootServiceProviderAccessor))] +public class RootServiceProviderAccessor : IRootServiceProviderAccessor, ISingletonDependency +{ + public IServiceProvider ServiceProvider { get; } + + public RootServiceProviderAccessor(IObjectAccessor objectAccessor) + { + ServiceProvider = objectAccessor.Value; + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs index 4ce2bf1d36..f51cb8d573 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs @@ -1,6 +1,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Shouldly; +using Volo.Abp.DependencyInjection; using Volo.Abp.Modularity; using Volo.Abp.Modularity.PlugIns; using Xunit; @@ -157,4 +158,19 @@ public class AbpApplication_Initialize_Tests application.Services.GetApplicationName().ShouldBe(applicationName); } } + + [Fact] + public async Task Should_Resolve_Root_Service_Provider() + { + using (var application = await AbpApplicationFactory.CreateAsync()) + { + await application.InitializeAsync(); + + application + .ServiceProvider + .GetRequiredService() + .ServiceProvider + .ShouldBeSameAs(application.ServiceProvider); + } + } } From b3bdcd80b83a77b4cd7b8977fd02b31ca798694e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 17:37:29 +0300 Subject: [PATCH 16/70] Change IRootServiceProviderAccessor as IRootServiceProvider --- .../IRootServiceProviderAccessor.cs | 8 +++++--- .../RootServiceProvider.cs | 19 +++++++++++++++++++ .../RootServiceProviderAccessor.cs | 14 -------------- .../Abp/AbpApplication_Initialize_Tests.cs | 7 +++---- 4 files changed, 27 insertions(+), 21 deletions(-) create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProvider.cs delete mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs index cb22e45287..8a3c1d09a5 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs @@ -1,12 +1,14 @@ -namespace Volo.Abp.DependencyInjection; +using System; + +namespace Volo.Abp.DependencyInjection; /// -/// Gets the root service provider of the application. +/// The root service provider of the application. /// Be careful to use the root service provider since there is no way /// to release/dispose objects resolved from the root service provider. /// So, always create a new scope if you need to resolve any service. /// -public interface IRootServiceProviderAccessor : IServiceProviderAccessor +public interface IRootServiceProvider : IServiceProvider { } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProvider.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProvider.cs new file mode 100644 index 0000000000..cbb6fb8984 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProvider.cs @@ -0,0 +1,19 @@ +using System; + +namespace Volo.Abp.DependencyInjection; + +[ExposeServices(typeof(IRootServiceProvider))] +public class RootServiceProvider : IRootServiceProvider, ISingletonDependency +{ + protected IServiceProvider ServiceProvider { get; } + + public RootServiceProvider(IObjectAccessor objectAccessor) + { + ServiceProvider = objectAccessor.Value; + } + + public virtual object GetService(Type serviceType) + { + return ServiceProvider.GetService(serviceType); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs deleted file mode 100644 index 1f0639be12..0000000000 --- a/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/RootServiceProviderAccessor.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Volo.Abp.DependencyInjection; - -[ExposeServices(typeof(IRootServiceProviderAccessor))] -public class RootServiceProviderAccessor : IRootServiceProviderAccessor, ISingletonDependency -{ - public IServiceProvider ServiceProvider { get; } - - public RootServiceProviderAccessor(IObjectAccessor objectAccessor) - { - ServiceProvider = objectAccessor.Value; - } -} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs index f51cb8d573..60f5028caa 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs @@ -165,12 +165,11 @@ public class AbpApplication_Initialize_Tests using (var application = await AbpApplicationFactory.CreateAsync()) { await application.InitializeAsync(); - + application .ServiceProvider - .GetRequiredService() - .ServiceProvider - .ShouldBeSameAs(application.ServiceProvider); + .GetRequiredService() + .ShouldNotBeNull(); } } } From aec6c5359852c3bcd4d62e9b61b0bfc75b69f764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 11 Aug 2022 17:37:49 +0300 Subject: [PATCH 17/70] Define IPermissionDefinitionRecordRepository.FindByNameAsync --- .../IPermissionDefinitionRecordRepository.cs | 6 +++++- ...EfCorePermissionDefinitionRecordRepository.cs | 13 +++++++++++++ .../MongoPermissionDefinitionRecordRepository.cs | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs index c333db97d5..e332d8483d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs @@ -1,9 +1,13 @@ using System; +using System.Threading; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; namespace Volo.Abp.PermissionManagement; public interface IPermissionDefinitionRecordRepository : IBasicRepository { - + Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs index 0aa44d7b98..09cf408f7d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs @@ -1,4 +1,8 @@ using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; @@ -13,4 +17,13 @@ public class EfCorePermissionDefinitionRecordRepository : : base(dbContextProvider) { } + + public async Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync(r => r.Name == name, cancellationToken); + } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs index 5b2ade05e4..e4894a1442 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs @@ -1,4 +1,7 @@ using System; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver.Linq; using Volo.Abp.Domain.Repositories.MongoDB; using Volo.Abp.MongoDB; @@ -13,4 +16,17 @@ public class MongoPermissionDefinitionRecordRepository : : base(dbContextProvider) { } + + public async Task FindByNameAsync( + string name, + CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + return await (await GetMongoQueryableAsync(cancellationToken)) + .OrderBy(x => x.Id) + .FirstOrDefaultAsync( + s => s.Name == name, + cancellationToken + ); + } } \ No newline at end of file From 215184347f4ab9b7a78b82411fa3e4b0327bdf58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 12 Aug 2022 14:20:00 +0300 Subject: [PATCH 18/70] Serialize PermissionDefinition to PermissionDefinitionRecord --- .../IPermissionDefinitionSerializer.cs | 21 +++++ .../PermissionDefinitionRecord.cs | 2 +- .../PermissionDefinitionSerializer.cs | 88 +++++++++++++++++++ .../PermissionDefinitionSerializer_Tests.cs | 62 +++++++++++++ 4 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs create mode 100644 modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs new file mode 100644 index 0000000000..152d37f9b9 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.PermissionManagement; + +public interface IPermissionDefinitionSerializer +{ + public Task SerializeAsync( + PermissionDefinition permission, + [CanBeNull] PermissionGroupDefinition permissionGroup); + + public Task DeserializeAsync( + PermissionDefinitionRecord permissionRecord); + + public Task SerializeAsync( + PermissionGroupDefinition permissionGroup); + + public Task DeserializeAsync( + PermissionGroupDefinitionRecord permissionGroupRecord); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs index ec2e35136d..f2a9173140 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -51,7 +51,7 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro { GroupName = Check.NotNullOrWhiteSpace(groupName, nameof(groupName), PermissionGroupDefinitionRecordConsts.MaxNameLength); Name = Check.NotNullOrWhiteSpace(name, nameof(name), PermissionDefinitionRecordConsts.MaxNameLength); - ParentName = Check.NotNullOrWhiteSpace(parentName, nameof(parentName), PermissionDefinitionRecordConsts.MaxNameLength); + ParentName = Check.Length(parentName, nameof(parentName), PermissionDefinitionRecordConsts.MaxNameLength); DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), PermissionDefinitionRecordConsts.MaxDisplayNameLength); IsEnabled = isEnabled; MultiTenancySide = multiTenancySide; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs new file mode 100644 index 0000000000..b2922f198e --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.Localization; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.Localization; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, ITransientDependency +{ + protected IGuidGenerator GuidGenerator { get; } + protected IStringLocalizerFactory StringLocalizerFactory { get; } + + public PermissionDefinitionSerializer( + IGuidGenerator guidGenerator, + IStringLocalizerFactory stringLocalizerFactory) + { + GuidGenerator = guidGenerator; + StringLocalizerFactory = stringLocalizerFactory; + } + + public Task SerializeAsync( + PermissionDefinition permission, + PermissionGroupDefinition permissionGroup) + { + using (CultureHelper.Use(CultureInfo.InvariantCulture)) + { + var permissionRecord = new PermissionDefinitionRecord( + GuidGenerator.Create(), + permissionGroup?.Name, + permission.Name, + permission.Parent?.Name, + permission.DisplayName.Localize(StringLocalizerFactory), + permission.IsEnabled, + permission.MultiTenancySide, + SerializeProviders(permission.Providers), + SerializeStateCheckers(permission.StateCheckers) + ); + + foreach (var property in permission.Properties) + { + permissionRecord.SetProperty(property.Key, property.Value); + } + + return Task.FromResult(permissionRecord); + } + } + + public Task DeserializeAsync(PermissionDefinitionRecord permissionRecord) + { + throw new System.NotImplementedException(); + } + + public Task SerializeAsync(PermissionGroupDefinition permissionGroup) + { + throw new System.NotImplementedException(); + } + + public Task DeserializeAsync(PermissionGroupDefinitionRecord permissionGroupRecord) + { + throw new System.NotImplementedException(); + } + + protected virtual string SerializeStateCheckers(IEnumerable> stateCheckers) + { + //TODO: Serialize state checker + + if(!stateCheckers.Any()) + { + return null; + } + + return null; + } + + protected virtual string SerializeProviders(ICollection providers) + { + return providers.Any() + ? providers.JoinAsString(",") + : null; + } +} \ No newline at end of file diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs new file mode 100644 index 0000000000..062e0e30c5 --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -0,0 +1,62 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Data; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; +using Xunit; + +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionSerializer_Tests : PermissionTestBase +{ + private readonly IPermissionDefinitionSerializer _serializer; + + public PermissionDefinitionSerializer_Tests() + { + _serializer = GetRequiredService(); + } + + [Fact] + public async Task Serialize_Permission_Definitions() + { + // Arrange + + var context = new PermissionDefinitionContext(null); + var group1 = CreatePermissionGroup1(context); + var permission1 = group1.AddPermission( + "Permission1", + new FixedLocalizableString("Permission one"), + MultiTenancySides.Tenant + ); + + permission1["CustomProperty2"] = "CustomValue2"; + + // Act + + var permissionRecord = await _serializer.SerializeAsync( + group1.GetPermissionOrNull("Permission1"), + group1 + ); + + //Assert + + permissionRecord.Name.ShouldBe("Permission1"); + permissionRecord.GroupName.ShouldBe("Group1"); + permissionRecord.DisplayName.ShouldBe("Permission one"); + permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); + } + + private static PermissionGroupDefinition CreatePermissionGroup1( + IPermissionDefinitionContext context) + { + var group = context.AddGroup( + "Group1", + displayName: new FixedLocalizableString("Group one") + ); + + group["CustomProperty1"] = "CustomValue1"; + + return group; + } +} \ No newline at end of file From 02fa508f4636cd55118799ce0bd812d8ce3b3120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 12 Aug 2022 14:27:22 +0300 Subject: [PATCH 19/70] Update PermissionDefinitionSerializer_Tests.cs --- .../PermissionDefinitionSerializer_Tests.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index 062e0e30c5..36de460470 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -18,24 +18,24 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase } [Fact] - public async Task Serialize_Permission_Definitions() + public async Task Serialize_Complex_Permission_Definition() { // Arrange var context = new PermissionDefinitionContext(null); var group1 = CreatePermissionGroup1(context); var permission1 = group1.AddPermission( - "Permission1", - new FixedLocalizableString("Permission one"), - MultiTenancySides.Tenant - ); - - permission1["CustomProperty2"] = "CustomValue2"; + "Permission1", + new FixedLocalizableString("Permission one"), + MultiTenancySides.Tenant + ) + .WithProviders("ProviderA", "ProviderB") + .WithProperty("CustomProperty2", "CustomValue2"); // Act var permissionRecord = await _serializer.SerializeAsync( - group1.GetPermissionOrNull("Permission1"), + permission1, group1 ); @@ -45,6 +45,8 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.GroupName.ShouldBe("Group1"); permissionRecord.DisplayName.ShouldBe("Permission one"); permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); + permissionRecord.Providers.ShouldBe("ProviderA,ProviderB"); + permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); } private static PermissionGroupDefinition CreatePermissionGroup1( From 6359d013bd22b1f7ce30d2289a61eb0eee723cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 12 Aug 2022 15:56:21 +0300 Subject: [PATCH 20/70] Introduce ISimpleStateCheckerSerializer and implement serialization of global feature requirements. --- .../ISimpleStateChecker.cs | 2 +- .../ISimpleStateCheckerSerializer.cs | 10 ++++ ...SimpleStateCheckerSerializerContributor.cs | 15 +++++ .../SimpleStateCheckerSerializer.cs | 56 +++++++++++++++++++ .../SimpleStateCheckerSerializerExtensions.cs | 38 +++++++++++++ ...SimpleStateCheckerSerializerContributor.cs | 54 ++++++++++++++++++ ...RequireGlobalFeaturesSimpleStateChecker.cs | 18 +++--- ...StateCheckerSerializerContributor_Tests.cs | 46 +++++++++++++++ .../PermissionDefinitionSerializer.cs | 20 +++---- ...p.PermissionManagement.Domain.Tests.csproj | 2 + .../AbpPermissionManagementTestModule.cs | 7 ++- .../PermissionDefinitionSerializer_Tests.cs | 6 +- 12 files changed, 251 insertions(+), 23 deletions(-) create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs create mode 100644 framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs create mode 100644 framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs index f1a2e40425..e919b981a6 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateChecker.cs @@ -6,4 +6,4 @@ public interface ISimpleStateChecker where TState : IHasSimpleStateCheckers { Task IsEnabledAsync(SimpleStateCheckerContext context); -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs new file mode 100644 index 0000000000..30d1ada0f2 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs @@ -0,0 +1,10 @@ +namespace Volo.Abp.SimpleStateChecking; + +public interface ISimpleStateCheckerSerializer +{ + public string Serialize(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers; + + public ISimpleStateChecker Deserialize(string value) + where TState : IHasSimpleStateCheckers; +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..b36c41347e --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Nodes; +using JetBrains.Annotations; + +namespace Volo.Abp.SimpleStateChecking; + +public interface ISimpleStateCheckerSerializerContributor +{ + [CanBeNull] + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers; + + [CanBeNull] + public ISimpleStateChecker Deserialize(JsonObject jsonObject) + where TState : IHasSimpleStateCheckers; +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs new file mode 100644 index 0000000000..5943dd4509 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using JetBrains.Annotations; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SimpleStateChecking; + +public class SimpleStateCheckerSerializer : + ISimpleStateCheckerSerializer, + ITransientDependency +{ + private readonly IEnumerable _contributors; + + public SimpleStateCheckerSerializer(IEnumerable contributors) + { + _contributors = contributors; + } + + [CanBeNull] + public string Serialize(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + foreach (var contributor in _contributors) + { + var result = contributor.SerializeToJson(checker); + if (result != null) + { + return result; + } + } + + return null; + } + + [CanBeNull] + public ISimpleStateChecker Deserialize(string value) + where TState : IHasSimpleStateCheckers + { + var jsonObject = JsonNode.Parse(value) as JsonObject; + if (jsonObject == null) + { + throw new AbpException("The value is not a JSON object: " + value); + } + + foreach (var contributor in _contributors) + { + var result = contributor.Deserialize(jsonObject); + if (result != null) + { + return result; + } + } + + return null; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs new file mode 100644 index 0000000000..b43a3d9b98 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Volo.Abp.SimpleStateChecking; + +public static class SimpleStateCheckerSerializerExtensions +{ + public static string Serialize( + this ISimpleStateCheckerSerializer serializer, + IList> stateCheckers) + where TState : IHasSimpleStateCheckers + { + switch (stateCheckers.Count) + { + case 0: + return null; + case 1: + return $"[{serializer.Serialize(stateCheckers.Single())}]"; + default: + var stringBuilder = new StringBuilder("["); + + for (var i = 0; i < stateCheckers.Count; i++) + { + if (i > 0) + { + stringBuilder.Append(","); + } + + stringBuilder.Append(serializer.Serialize(stateCheckers[i])); + } + + stringBuilder.Append("]"); + + return stringBuilder.ToString(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..0ce0a0bfcd --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,54 @@ +using System.Linq; +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.GlobalFeatures; + +public class GlobalFeaturesSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ITransientDependency +{ + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireGlobalFeaturesSimpleStateChecker globalFeaturesSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = "GF", + ["A"] = globalFeaturesSimpleStateChecker.RequiresAll + }; + + var nameArray = new JsonArray(); + foreach (var globalFeatureName in globalFeaturesSimpleStateChecker.GlobalFeatureNames) + { + nameArray.Add(globalFeatureName); + } + + jsonObject["N"] = nameArray; + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize(JsonObject jsonObject) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != "GF") + { + return null; + } + + var nameArray = jsonObject["N"] as JsonArray; + if (nameArray == null) + { + throw new AbpException("'N' is not an array in the serialized state checker! JsonObject: " + jsonObject.ToJsonString()); + } + + return new RequireGlobalFeaturesSimpleStateChecker( + (bool?)jsonObject["A"] ?? false, + nameArray.Select(x => x.ToString()).ToArray() + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs index 77fdaa0e1e..d37aba8397 100644 --- a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/RequireGlobalFeaturesSimpleStateChecker.cs @@ -8,8 +8,8 @@ namespace Volo.Abp.GlobalFeatures; public class RequireGlobalFeaturesSimpleStateChecker : ISimpleStateChecker where TState : IHasSimpleStateCheckers { - private readonly string[] _globalFeatureNames; - private readonly bool _requiresAll; + public string[] GlobalFeatureNames { get; } + public bool RequiresAll { get; } public RequireGlobalFeaturesSimpleStateChecker(params string[] globalFeatureNames) : this(true, globalFeatureNames) @@ -20,23 +20,23 @@ public class RequireGlobalFeaturesSimpleStateChecker : ISimpleStateCheck { Check.NotNullOrEmpty(globalFeatureNames, nameof(globalFeatureNames)); - _requiresAll = requiresAll; - _globalFeatureNames = globalFeatureNames; + RequiresAll = requiresAll; + GlobalFeatureNames = globalFeatureNames; } public RequireGlobalFeaturesSimpleStateChecker(bool requiresAll, params Type[] globalFeatureNames) { Check.NotNullOrEmpty(globalFeatureNames, nameof(globalFeatureNames)); - _requiresAll = requiresAll; - _globalFeatureNames = globalFeatureNames.Select(GlobalFeatureNameAttribute.GetName).ToArray(); + RequiresAll = requiresAll; + GlobalFeatureNames = globalFeatureNames.Select(GlobalFeatureNameAttribute.GetName).ToArray(); } public Task IsEnabledAsync(SimpleStateCheckerContext context) { - var isEnabled = _requiresAll - ? _globalFeatureNames.All(x => GlobalFeatureManager.Instance.IsEnabled(x)) - : _globalFeatureNames.Any(x => GlobalFeatureManager.Instance.IsEnabled(x)); + var isEnabled = RequiresAll + ? GlobalFeatureNames.All(x => GlobalFeatureManager.Instance.IsEnabled(x)) + : GlobalFeatureNames.Any(x => GlobalFeatureManager.Instance.IsEnabled(x)); return Task.FromResult(isEnabled); } diff --git a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs new file mode 100644 index 0000000000..46064bd11e --- /dev/null +++ b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Shouldly; +using Volo.Abp.SimpleStateChecking; +using Xunit; + +namespace Volo.Abp.GlobalFeatures; + +public class GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests +{ + [Fact] + public void Should_Serialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new GlobalFeaturesSimpleStateCheckerSerializerContributor(); + + var result = serializer.SerializeToJson( + new RequireGlobalFeaturesSimpleStateChecker( + "FeatureA", + "FeatureB" + ) + ); + + result.ShouldBe("{\"T\":\"GF\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + } + + [Fact] + public void Should_Deserialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new GlobalFeaturesSimpleStateCheckerSerializerContributor(); + + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"GF\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + var checker = serializer.Deserialize(jsonObject); + + checker.ShouldBeOfType>(); + var globalFeaturesSimpleStateChecker = checker as RequireGlobalFeaturesSimpleStateChecker; + globalFeaturesSimpleStateChecker.ShouldNotBeNull(); + globalFeaturesSimpleStateChecker.RequiresAll.ShouldBeTrue(); + globalFeaturesSimpleStateChecker.GlobalFeatureNames[0].ShouldBe("FeatureA"); + globalFeaturesSimpleStateChecker.GlobalFeatureNames[1].ShouldBe("FeatureB"); + } + + private class MyState : IHasSimpleStateCheckers + { + public List> StateCheckers { get; } = new(); + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index b2922f198e..47abbc97eb 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Localization; using Volo.Abp.Authorization.Permissions; @@ -14,13 +15,16 @@ namespace Volo.Abp.PermissionManagement; public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, ITransientDependency { + protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } protected IGuidGenerator GuidGenerator { get; } protected IStringLocalizerFactory StringLocalizerFactory { get; } public PermissionDefinitionSerializer( IGuidGenerator guidGenerator, - IStringLocalizerFactory stringLocalizerFactory) + IStringLocalizerFactory stringLocalizerFactory, + ISimpleStateCheckerSerializer stateCheckerSerializer) { + StateCheckerSerializer = stateCheckerSerializer; GuidGenerator = guidGenerator; StringLocalizerFactory = stringLocalizerFactory; } @@ -52,7 +56,8 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I } } - public Task DeserializeAsync(PermissionDefinitionRecord permissionRecord) + public Task DeserializeAsync( + PermissionDefinitionRecord permissionRecord) { throw new System.NotImplementedException(); } @@ -67,16 +72,9 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I throw new System.NotImplementedException(); } - protected virtual string SerializeStateCheckers(IEnumerable> stateCheckers) + protected virtual string SerializeStateCheckers(List> stateCheckers) { - //TODO: Serialize state checker - - if(!stateCheckers.Any()) - { - return null; - } - - return null; + return StateCheckerSerializer.Serialize(stateCheckers); } protected virtual string SerializeProviders(ICollection providers) diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj index 9b0cd2f1c0..8e77b2d56c 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo.Abp.PermissionManagement.Domain.Tests.csproj @@ -12,6 +12,8 @@ + + diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs index 24945f83b0..bf32af126d 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs @@ -2,6 +2,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Features; +using Volo.Abp.GlobalFeatures; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.Uow; @@ -10,7 +12,10 @@ namespace Volo.Abp.PermissionManagement; [DependsOn( typeof(AbpPermissionManagementEntityFrameworkCoreModule), - typeof(AbpPermissionManagementTestBaseModule))] + typeof(AbpPermissionManagementTestBaseModule), + typeof(AbpFeaturesModule), + typeof(AbpGlobalFeaturesModule) + )] public class AbpPermissionManagementTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index 36de460470..35a7961e11 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -2,6 +2,8 @@ using Shouldly; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; +using Volo.Abp.Features; +using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Xunit; @@ -30,7 +32,8 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase MultiTenancySides.Tenant ) .WithProviders("ProviderA", "ProviderB") - .WithProperty("CustomProperty2", "CustomValue2"); + .WithProperty("CustomProperty2", "CustomValue2") + .RequireGlobalFeatures("GlobalFeature1", "GlobalFeature2"); // Act @@ -47,6 +50,7 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); permissionRecord.Providers.ShouldBe("ProviderA,ProviderB"); permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); + permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"GF\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]}]"); } private static PermissionGroupDefinition CreatePermissionGroup1( From acc5789a7ef05681c3ec657b3eb9c3ad82b16064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 12 Aug 2022 16:29:02 +0300 Subject: [PATCH 21/70] state chakers can be singleton. --- .../Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs | 2 +- .../GlobalFeaturesSimpleStateCheckerSerializerContributor.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs index 5943dd4509..21cddb437f 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.SimpleStateChecking; public class SimpleStateCheckerSerializer : ISimpleStateCheckerSerializer, - ITransientDependency + ISingletonDependency { private readonly IEnumerable _contributors; diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs index 0ce0a0bfcd..00f72e423d 100644 --- a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs @@ -7,7 +7,7 @@ namespace Volo.Abp.GlobalFeatures; public class GlobalFeaturesSimpleStateCheckerSerializerContributor : ISimpleStateCheckerSerializerContributor, - ITransientDependency + ISingletonDependency { public string SerializeToJson(ISimpleStateChecker checker) where TState : IHasSimpleStateCheckers From 65f21a7b700b952f85973961c1ba6beae13de041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 12 Aug 2022 17:12:12 +0300 Subject: [PATCH 22/70] Serialize PermissionGroupDefinition groups --- .../PermissionDefinitionSerializer.cs | 16 ++++- .../PermissionDefinitionSerializer_Tests.cs | 58 ++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index 47abbc97eb..13276be20b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -64,7 +64,21 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I public Task SerializeAsync(PermissionGroupDefinition permissionGroup) { - throw new System.NotImplementedException(); + using (CultureHelper.Use(CultureInfo.InvariantCulture)) + { + var permissionGroupRecord = new PermissionGroupDefinitionRecord( + GuidGenerator.Create(), + permissionGroup.Name, + permissionGroup.DisplayName.Localize(StringLocalizerFactory) + ); + + foreach (var property in permissionGroup.Properties) + { + permissionGroupRecord.SetProperty(property.Key, property.Value); + } + + return Task.FromResult(permissionGroupRecord); + } } public Task DeserializeAsync(PermissionGroupDefinitionRecord permissionGroupRecord) diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index 35a7961e11..cac2892838 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.Linq; +using System.Threading.Tasks; using Shouldly; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; @@ -18,6 +20,25 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase { _serializer = GetRequiredService(); } + + [Fact] + public async Task Serialize_Permission_Group_Definition() + { + // Arrange + + var context = new PermissionDefinitionContext(null); + var group1 = CreatePermissionGroup1(context); + + // Act + + var permissionGroupRecord = await _serializer.SerializeAsync(group1); + + //Assert + + permissionGroupRecord.Name.ShouldBe("Group1"); + permissionGroupRecord.DisplayName.ShouldBe("Group one"); + permissionGroupRecord.GetProperty("CustomProperty1").ShouldBe("CustomValue1"); + } [Fact] public async Task Serialize_Complex_Permission_Definition() @@ -52,6 +73,41 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"GF\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]}]"); } + + [Fact(Skip = "Not implemented yet")] + public async Task Deserialize_Complex_Permission_Definition() + { + // Arrange + + var permissionRecord = new PermissionDefinitionRecord + { + Name = "Permission1", + GroupName = "Group1", + DisplayName = "Permission one", + Providers = "ProviderA,ProviderB", + IsEnabled = true, + MultiTenancySide = MultiTenancySides.Tenant, + StateCheckers = "[{\"T\":\"GF\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]}]" + }; + + // Act + + var permission = await _serializer.DeserializeAsync(permissionRecord); + + //Assert + + permission.Name.ShouldBe("Permission1"); + permission.DisplayName.ShouldBeOfType(); + permission.DisplayName.As().Value.ShouldBe("Permission one"); + permission.Parent.ShouldBeNull(); + permission.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); + permission.IsEnabled.ShouldBe(true); + permission.Providers.Count.ShouldBe(2); + permission.Providers.ShouldContain("ProviderA"); + permission.Providers.ShouldContain("ProviderB"); + permission.StateCheckers.Count.ShouldBe(1); + permission.StateCheckers[0].ShouldBeOfType>(); + } private static PermissionGroupDefinition CreatePermissionGroup1( IPermissionDefinitionContext context) From f37ad5eec38f2df1ecc77a9b9ba063d7b8aa8a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 12 Aug 2022 17:41:43 +0300 Subject: [PATCH 23/70] Created initial IStaticPermissionSaver --- .../AbpPermissionManagementDomainModule.cs | 35 +++++++- .../DynamicPermissionDefinitionStore.cs | 79 +++++++++++++++++++ .../IStaticPermissionSaver.cs | 8 ++ .../StaticPermissionSaver.cs | 47 +++++++++++ 4 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IStaticPermissionSaver.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index 6dff7bf663..de5c7a0559 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -1,8 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Logging; using Volo.Abp.Authorization; using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; using Volo.Abp.Domain; using Volo.Abp.Json; using Volo.Abp.Modularity; @@ -16,5 +18,30 @@ namespace Volo.Abp.PermissionManagement; [DependsOn(typeof(AbpJsonModule))] public class AbpPermissionManagementDomainModule : AbpModule { - -} + public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + Task.Run(async () => + { + using var scope = context + .ServiceProvider + .GetRequiredService() + .CreateScope(); + + try + { + await scope + .ServiceProvider + .GetRequiredService() + .SaveAsync(); + } + catch (Exception ex) + { + //TODO: We should retry until it's successful! + + scope.ServiceProvider + .GetService>() + .LogException(ex); + } + }); + } +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs new file mode 100644 index 0000000000..6c4ea1fdec --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.PermissionManagement; + +/* + +[Dependency(ReplaceServices = true)] +public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ITransientDependency +{ + protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; } + protected IPermissionDefinitionRecordRepository PermissionRepository { get; } + protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; } + + public DynamicPermissionDefinitionStore( + IPermissionGroupDefinitionRecordRepository permissionGroupRepository, + IPermissionDefinitionRecordRepository permissionRepository, + IPermissionDefinitionSerializer permissionDefinitionSerializer) + { + PermissionGroupRepository = permissionGroupRepository; + PermissionRepository = permissionRepository; + PermissionDefinitionSerializer = permissionDefinitionSerializer; + } + + public virtual async Task GetOrNullAsync(string name) + { + var permissionRecord = await PermissionRepository.FindByNameAsync(name); + if (permissionRecord == null) + { + return null; + } + + return await PermissionDefinitionSerializer.DeserializeAsync(permissionRecord); + } + + public virtual async Task> GetPermissionsAsync() + { + var permissionRecords = await PermissionRepository.GetListAsync(); + if(permissionRecords.Count == 0) + { + return Array.Empty(); + } + + var permissionDefinitions = new PermissionDefinition[permissionRecords.Count]; + for (var i = 0; i < permissionRecords.Count; i++) + { + permissionDefinitions[i] = await PermissionDefinitionSerializer.DeserializeAsync(permissionRecords[i]); + } + + return permissionDefinitions; + } + + public virtual async Task> GetGroupsAsync() + { + var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); + if(permissionGroupRecords.Count == 0) + { + return Array.Empty(); + } + + var permissionGroupDefinitions = new PermissionGroupDefinition[permissionGroupRecords.Count]; + for (var i = 0; i < permissionGroupRecords.Count; i++) + { + permissionGroupDefinitions[i] = await PermissionDefinitionSerializer.DeserializeAsync(permissionGroupRecords[i]); + } + + return permissionGroupDefinitions; + } + + public virtual async Task StoreStaticPermissionsAsync() + { + throw new NotImplementedException(); + } +} + +*/ \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IStaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IStaticPermissionSaver.cs new file mode 100644 index 0000000000..5c91636c3d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IStaticPermissionSaver.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.PermissionManagement; + +public interface IStaticPermissionSaver +{ + Task SaveAsync(); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs new file mode 100644 index 0000000000..34f8752253 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Uow; + +namespace Volo.Abp.PermissionManagement; + +public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependency +{ + protected IStaticPermissionDefinitionStore StaticStore { get; } + protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; } + protected IPermissionDefinitionRecordRepository PermissionRepository { get; } + protected IPermissionDefinitionSerializer PermissionSerializer { get; } + + public StaticPermissionSaver( + IStaticPermissionDefinitionStore staticStore, + IPermissionGroupDefinitionRecordRepository permissionGroupRepository, + IPermissionDefinitionRecordRepository permissionRepository, + IPermissionDefinitionSerializer permissionSerializer) + { + StaticStore = staticStore; + PermissionGroupRepository = permissionGroupRepository; + PermissionRepository = permissionRepository; + PermissionSerializer = permissionSerializer; + } + + [UnitOfWork] + public virtual async Task SaveAsync() + { + // TODO: Save only changed permissions & groups + /* - get all groups + * - compare and update or insert groups + * - get all permissions + * - compare and update or insert permissions + * - set in-memory cache using the latest group and permission data + */ + + var permissionGroups = await StaticStore.GetGroupsAsync(); + foreach (var permissionGroup in permissionGroups) + { + foreach (var permission in permissionGroup.GetPermissionsWithChildren()) + { + + } + } + } +} \ No newline at end of file From edbe4aa6e31e151cde105b99719272003435cad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 12 Aug 2022 18:42:23 +0300 Subject: [PATCH 24/70] Introduce DynamicPermissionDefinitionStoreCache (initial) --- .../ISimpleStateCheckerSerializer.cs | 4 +- .../SimpleStateCheckerSerializer.cs | 8 +- .../SimpleStateCheckerSerializerExtensions.cs | 44 +++++++ .../DynamicPermissionDefinitionStore.cs | 26 ++-- .../DynamicPermissionDefinitionStoreCache.cs | 111 ++++++++++++++++++ 5 files changed, 168 insertions(+), 25 deletions(-) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs index 30d1ada0f2..00191b03d2 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs @@ -1,3 +1,5 @@ +using System.Text.Json.Nodes; + namespace Volo.Abp.SimpleStateChecking; public interface ISimpleStateCheckerSerializer @@ -5,6 +7,6 @@ public interface ISimpleStateCheckerSerializer public string Serialize(ISimpleStateChecker checker) where TState : IHasSimpleStateCheckers; - public ISimpleStateChecker Deserialize(string value) + public ISimpleStateChecker Deserialize(JsonObject jsonObject) where TState : IHasSimpleStateCheckers; } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs index 21cddb437f..9e7cfd47f7 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs @@ -33,15 +33,9 @@ public class SimpleStateCheckerSerializer : } [CanBeNull] - public ISimpleStateChecker Deserialize(string value) + public ISimpleStateChecker Deserialize(JsonObject jsonObject) where TState : IHasSimpleStateCheckers { - var jsonObject = JsonNode.Parse(value) as JsonObject; - if (jsonObject == null) - { - throw new AbpException("The value is not a JSON object: " + value); - } - foreach (var contributor in _contributors) { var result = contributor.Deserialize(jsonObject); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs index b43a3d9b98..c5fbb824b3 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs @@ -1,6 +1,8 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json.Nodes; namespace Volo.Abp.SimpleStateChecking; @@ -35,4 +37,46 @@ public static class SimpleStateCheckerSerializerExtensions return stringBuilder.ToString(); } } + + public static ISimpleStateChecker[] DeserializeArray( + this ISimpleStateCheckerSerializer serializer, + string value) + where TState : IHasSimpleStateCheckers + { + if (value.IsNullOrWhiteSpace()) + { + return Array.Empty>(); + } + + var array = JsonNode.Parse(value) as JsonArray; + if (array == null || array.Count == 0) + { + return Array.Empty>(); + } + + if (array.Count == 1) + { + var jsonObject = array[0] as JsonObject; + if (jsonObject == null) + { + throw new AbpException("JSON value is not an array of objects: " + value); + } + + return new[] { serializer.Deserialize(jsonObject) }; + } + + var checkers = new ISimpleStateChecker[array.Count]; + + for (var i = 0; i < array.Count; i++) + { + if (array[i] is not JsonObject jsonObject) + { + throw new AbpException("JSON value is not an array of objects: " + value); + } + + checkers[i] = serializer.Deserialize(jsonObject); + } + + return checkers; + } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index 6c4ea1fdec..b8e995de9d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -6,8 +6,6 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.PermissionManagement; -/* - [Dependency(ReplaceServices = true)] public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ITransientDependency { @@ -24,7 +22,7 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor PermissionRepository = permissionRepository; PermissionDefinitionSerializer = permissionDefinitionSerializer; } - + public virtual async Task GetOrNullAsync(string name) { var permissionRecord = await PermissionRepository.FindByNameAsync(name); @@ -32,18 +30,18 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor { return null; } - + return await PermissionDefinitionSerializer.DeserializeAsync(permissionRecord); } public virtual async Task> GetPermissionsAsync() { var permissionRecords = await PermissionRepository.GetListAsync(); - if(permissionRecords.Count == 0) + if (permissionRecords.Count == 0) { return Array.Empty(); } - + var permissionDefinitions = new PermissionDefinition[permissionRecords.Count]; for (var i = 0; i < permissionRecords.Count; i++) { @@ -56,24 +54,18 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor public virtual async Task> GetGroupsAsync() { var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); - if(permissionGroupRecords.Count == 0) + if (permissionGroupRecords.Count == 0) { return Array.Empty(); } - + var permissionGroupDefinitions = new PermissionGroupDefinition[permissionGroupRecords.Count]; for (var i = 0; i < permissionGroupRecords.Count; i++) { - permissionGroupDefinitions[i] = await PermissionDefinitionSerializer.DeserializeAsync(permissionGroupRecords[i]); + permissionGroupDefinitions[i] = + await PermissionDefinitionSerializer.DeserializeAsync(permissionGroupRecords[i]); } return permissionGroupDefinitions; } - - public virtual async Task StoreStaticPermissionsAsync() - { - throw new NotImplementedException(); - } -} - -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs new file mode 100644 index 0000000000..5a53a62884 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.PermissionManagement; + +public class DynamicPermissionDefinitionStoreCache : ISingletonDependency +{ + public string CacheStamp { get; set; } + + protected IDictionary PermissionGroupDefinitions { get; } + + protected IDictionary PermissionDefinitions { get; } + protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } + + public DynamicPermissionDefinitionStoreCache(ISimpleStateCheckerSerializer stateCheckerSerializer) + { + StateCheckerSerializer = stateCheckerSerializer; + PermissionGroupDefinitions = new Dictionary(); + PermissionDefinitions = new Dictionary(); + } + + public async Task FillAsync( + List permissionGroupRecords, + List permissionRecords) + { + var context = new PermissionDefinitionContext(null); + + foreach (var permissionGroupRecord in permissionGroupRecords) + { + var permissionGroup = context.AddGroup( + permissionGroupRecord.Name, + new FixedLocalizableString(permissionGroupRecord.DisplayName) + ); + + foreach (var property in permissionGroupRecord.ExtraProperties) + { + permissionGroup[property.Key] = property.Value; + } + + var permissionRecordsInThisGroup = permissionRecords.Where(p => p.GroupName == permissionGroup.Name); + foreach (var permissionRecord in permissionRecordsInThisGroup) + { + var permission = permissionGroup.AddPermission( + permissionRecord.Name, + new FixedLocalizableString(permissionRecord.DisplayName), + permissionRecord.MultiTenancySide, + permissionRecord.IsEnabled + ); + + if (!permissionRecord.Providers.IsNullOrWhiteSpace()) + { + permission.Providers.AddRange(permissionRecord.Providers.Split(',')); + } + + if (!permissionRecord.StateCheckers.IsNullOrWhiteSpace()) + { + var checkers = StateCheckerSerializer + .DeserializeArray( + permissionRecord.StateCheckers + ); + permission.StateCheckers.AddRange(checkers); + } + + foreach (var property in permissionRecord.ExtraProperties) + { + permission[property.Key] = property.Value; + } + + //TODO: Child permissions! (with parent name setting) + } + } + } + + protected virtual Dictionary CreatePermissionDefinitions() + { + var permissions = new Dictionary(); + + foreach (var groupDefinition in PermissionGroupDefinitions.Values) + { + foreach (var permission in groupDefinition.Permissions) + { + AddPermissionToDictionaryRecursively(permissions, permission); + } + } + + return permissions; + } + + protected virtual void AddPermissionToDictionaryRecursively( + Dictionary permissions, + PermissionDefinition permission) + { + if (permissions.ContainsKey(permission.Name)) + { + throw new AbpException("Duplicate permission name: " + permission.Name); + } + + permissions[permission.Name] = permission; + + foreach (var child in permission.Children) + { + AddPermissionToDictionaryRecursively(permissions, child); + } + } +} \ No newline at end of file From 0bca3f0edf5dad3aeec55d2c111f138c96f70e81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 15:59:28 +0300 Subject: [PATCH 25/70] Introduce ICanAddChildPermission --- .../Permissions/ICanAddChildPermission.cs | 14 ++++++++++++++ .../Permissions/PermissionDefinition.cs | 14 +++++++++++++- .../Permissions/PermissionGroupDefinition.cs | 4 ++-- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs new file mode 100644 index 0000000000..57a224699f --- /dev/null +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/ICanAddChildPermission.cs @@ -0,0 +1,14 @@ +using JetBrains.Annotations; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Authorization.Permissions; + +public interface ICanAddChildPermission +{ + PermissionDefinition AddPermission( + [NotNull] string name, + ILocalizableString displayName = null, + MultiTenancySides multiTenancySide = MultiTenancySides.Both, + bool isEnabled = true); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs index 75d463f30f..fb6f07690c 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs @@ -7,7 +7,9 @@ using Volo.Abp.SimpleStateChecking; namespace Volo.Abp.Authorization.Permissions; -public class PermissionDefinition : IHasSimpleStateCheckers +public class PermissionDefinition : + IHasSimpleStateCheckers, + ICanAddChildPermission { /// /// Unique name of the permission. @@ -110,6 +112,16 @@ public class PermissionDefinition : IHasSimpleStateCheckers /// Sets a property in the dictionary. diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs index 6c3edd7f12..9fd904f54c 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs @@ -6,7 +6,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.Authorization.Permissions; -public class PermissionGroupDefinition +public class PermissionGroupDefinition : ICanAddChildPermission { /// /// Unique name of the group. @@ -49,7 +49,7 @@ public class PermissionGroupDefinition } public virtual PermissionDefinition AddPermission( - string name, + [NotNull] string name, ILocalizableString displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true) From f285b4a80b8ea0607069512e0072ccfde93319c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 16:00:15 +0300 Subject: [PATCH 26/70] Complete DynamicPermissionDefinitionStoreCache.FillAsync --- .../DynamicPermissionDefinitionStoreCache.cs | 77 +++++++++++-------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs index 5a53a62884..002121aeb3 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs @@ -9,6 +9,7 @@ using Volo.Abp.SimpleStateChecking; namespace Volo.Abp.PermissionManagement; +//TODO: Extract interface public class DynamicPermissionDefinitionStoreCache : ISingletonDependency { public string CacheStamp { get; set; } @@ -25,7 +26,7 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency PermissionDefinitions = new Dictionary(); } - public async Task FillAsync( + public Task FillAsync( List permissionGroupRecords, List permissionRecords) { @@ -35,7 +36,7 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency { var permissionGroup = context.AddGroup( permissionGroupRecord.Name, - new FixedLocalizableString(permissionGroupRecord.DisplayName) + new FixedLocalizableString(permissionGroupRecord.DisplayName) //TODO: Consider localization ); foreach (var property in permissionGroupRecord.ExtraProperties) @@ -43,40 +44,54 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency permissionGroup[property.Key] = property.Value; } - var permissionRecordsInThisGroup = permissionRecords.Where(p => p.GroupName == permissionGroup.Name); + var permissionRecordsInThisGroup = permissionRecords + .Where(p => p.GroupName == permissionGroup.Name); + foreach (var permissionRecord in permissionRecordsInThisGroup) { - var permission = permissionGroup.AddPermission( - permissionRecord.Name, - new FixedLocalizableString(permissionRecord.DisplayName), - permissionRecord.MultiTenancySide, - permissionRecord.IsEnabled - ); - - if (!permissionRecord.Providers.IsNullOrWhiteSpace()) - { - permission.Providers.AddRange(permissionRecord.Providers.Split(',')); - } - - if (!permissionRecord.StateCheckers.IsNullOrWhiteSpace()) - { - var checkers = StateCheckerSerializer - .DeserializeArray( - permissionRecord.StateCheckers - ); - permission.StateCheckers.AddRange(checkers); - } - - foreach (var property in permissionRecord.ExtraProperties) - { - permission[property.Key] = property.Value; - } - - //TODO: Child permissions! (with parent name setting) + AddPermissionRecursively(permissionGroup, permissionRecord, permissionRecords); } } + + return Task.CompletedTask; } - + + private void AddPermissionRecursively(ICanAddChildPermission permissionContainer, + PermissionDefinitionRecord permissionRecord, + List allPermissionRecords) + { + var permission = permissionContainer.AddPermission( + permissionRecord.Name, + new FixedLocalizableString(permissionRecord.DisplayName), + permissionRecord.MultiTenancySide, + permissionRecord.IsEnabled + ); + + if (!permissionRecord.Providers.IsNullOrWhiteSpace()) + { + permission.Providers.AddRange(permissionRecord.Providers.Split(',')); + } + + if (!permissionRecord.StateCheckers.IsNullOrWhiteSpace()) + { + var checkers = StateCheckerSerializer + .DeserializeArray( + permissionRecord.StateCheckers + ); + permission.StateCheckers.AddRange(checkers); + } + + foreach (var property in permissionRecord.ExtraProperties) + { + permission[property.Key] = property.Value; + } + + foreach (var subPermission in allPermissionRecords.Where(p => p.ParentName == permissionRecord.Name)) + { + AddPermissionRecursively(permission, subPermission, allPermissionRecords); + } + } + protected virtual Dictionary CreatePermissionDefinitions() { var permissions = new Dictionary(); From b162fd4ff86be7555e6347ea45bbdbbb2e77ea43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 16:22:54 +0300 Subject: [PATCH 27/70] serialize permissions to records. --- .../DynamicPermissionDefinitionStore.cs | 31 ++----------------- .../IPermissionDefinitionSerializer.cs | 14 ++++----- .../PermissionDefinitionSerializer.cs | 19 ++++++++++++ .../StaticPermissionSaver.cs | 16 +++++----- 4 files changed, 35 insertions(+), 45 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index b8e995de9d..966fca75ae 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -31,41 +31,16 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor return null; } - return await PermissionDefinitionSerializer.DeserializeAsync(permissionRecord); + throw new NotImplementedException(); } public virtual async Task> GetPermissionsAsync() { - var permissionRecords = await PermissionRepository.GetListAsync(); - if (permissionRecords.Count == 0) - { - return Array.Empty(); - } - - var permissionDefinitions = new PermissionDefinition[permissionRecords.Count]; - for (var i = 0; i < permissionRecords.Count; i++) - { - permissionDefinitions[i] = await PermissionDefinitionSerializer.DeserializeAsync(permissionRecords[i]); - } - - return permissionDefinitions; + throw new NotImplementedException(); } public virtual async Task> GetGroupsAsync() { - var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); - if (permissionGroupRecords.Count == 0) - { - return Array.Empty(); - } - - var permissionGroupDefinitions = new PermissionGroupDefinition[permissionGroupRecords.Count]; - for (var i = 0; i < permissionGroupRecords.Count; i++) - { - permissionGroupDefinitions[i] = - await PermissionDefinitionSerializer.DeserializeAsync(permissionGroupRecords[i]); - } - - return permissionGroupDefinitions; + throw new NotImplementedException(); } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs index 152d37f9b9..799896a5d8 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Threading.Tasks; using JetBrains.Annotations; using Volo.Abp.Authorization.Permissions; @@ -6,16 +7,13 @@ namespace Volo.Abp.PermissionManagement; public interface IPermissionDefinitionSerializer { - public Task SerializeAsync( + Task SerializeAsync( PermissionDefinition permission, [CanBeNull] PermissionGroupDefinition permissionGroup); - - public Task DeserializeAsync( - PermissionDefinitionRecord permissionRecord); - - public Task SerializeAsync( + + Task SerializeAsync( PermissionGroupDefinition permissionGroup); - public Task DeserializeAsync( - PermissionGroupDefinitionRecord permissionGroupRecord); + Task<(List, List)> + SerializeAsync(IEnumerable permissionGroups); } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index 13276be20b..bccfd65a7a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -81,6 +81,25 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I } } + public async Task<(List, List)> + SerializeAsync(IEnumerable permissionGroups) + { + var permissionGroupRecords = new List(); + var permissionRecords = new List(); + + foreach (var permissionGroup in permissionGroups) + { + permissionGroupRecords.Add(await SerializeAsync(permissionGroup)); + + foreach (var permission in permissionGroup.GetPermissionsWithChildren()) + { + permissionRecords.Add(await SerializeAsync(permission, permissionGroup)); + } + } + + return (permissionGroupRecords, permissionRecords); + } + public Task DeserializeAsync(PermissionGroupDefinitionRecord permissionGroupRecord) { throw new System.NotImplementedException(); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index 34f8752253..c3b1e85866 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; @@ -28,20 +29,17 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc public virtual async Task SaveAsync() { // TODO: Save only changed permissions & groups - /* - get all groups + /* + get all groups & perms * - compare and update or insert groups * - get all permissions * - compare and update or insert permissions * - set in-memory cache using the latest group and permission data */ + + var (permissionGroupRecords, permissionRecords) = await PermissionSerializer.SerializeAsync( + await StaticStore.GetGroupsAsync() + ); + - var permissionGroups = await StaticStore.GetGroupsAsync(); - foreach (var permissionGroup in permissionGroups) - { - foreach (var permission in permissionGroup.GetPermissionsWithChildren()) - { - - } - } } } \ No newline at end of file From f220de7fe3d47fc469783837ac65a60da7c949ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 16:40:37 +0300 Subject: [PATCH 28/70] Introduce IApplicationNameAccessor --- .../ServiceCollectionApplicationExtensions.cs | 2 +- .../Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs | 1 + .../Volo.Abp.Core/Volo/Abp/IAbpApplication.cs | 16 ++++++---------- .../Volo/Abp/IApplicationNameAccessor.cs | 11 +++++++++++ .../Volo/Abp/AbpApplication_Initialize_Tests.cs | 7 +++++++ 5 files changed, 26 insertions(+), 11 deletions(-) create mode 100644 framework/src/Volo.Abp.Core/Volo/Abp/IApplicationNameAccessor.cs diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs index 204d582ca5..72ce661ed5 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionApplicationExtensions.cs @@ -43,6 +43,6 @@ public static class ServiceCollectionApplicationExtensions [CanBeNull] public static string GetApplicationName(this IServiceCollection services) { - return services.GetSingletonInstance().ApplicationName; + return services.GetSingletonInstance().ApplicationName; } } diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs index e24403d0e3..87ddf14c1b 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs @@ -47,6 +47,7 @@ public abstract class AbpApplicationBase : IAbpApplication ApplicationName = options.ApplicationName; services.AddSingleton(this); + services.AddSingleton(this); services.AddSingleton(this); services.AddCoreServices(); diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs index e132df5a59..35542ee91f 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs @@ -5,7 +5,10 @@ using Volo.Abp.Modularity; namespace Volo.Abp; -public interface IAbpApplication : IModuleContainer, IDisposable +public interface IAbpApplication : + IModuleContainer, + IApplicationNameAccessor, + IDisposable { /// /// Type of the startup (entrance) module of the application. @@ -23,14 +26,7 @@ public interface IAbpApplication : IModuleContainer, IDisposable /// This can not be used before initialize the application. /// IServiceProvider ServiceProvider { get; } - - /// - /// Name of the application. - /// This is useful for systems with multiple applications, to distinguish - /// resources of the applications located together. - /// - string ApplicationName { get; } - + /// /// Calls the Pre/Post/ConfigureServicesAsync methods of the modules. /// If you use this method, you must have set the @@ -47,4 +43,4 @@ public interface IAbpApplication : IModuleContainer, IDisposable /// Used to gracefully shutdown the application and all modules. /// void Shutdown(); -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/IApplicationNameAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IApplicationNameAccessor.cs new file mode 100644 index 0000000000..0047fcbcdf --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/IApplicationNameAccessor.cs @@ -0,0 +1,11 @@ +namespace Volo.Abp; + +public interface IApplicationNameAccessor +{ + /// + /// Name of the application. + /// This is useful for systems with multiple applications, to distinguish + /// resources of the applications located together. + /// + string ApplicationName { get; } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs index 60f5028caa..9eff208198 100644 --- a/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs +++ b/framework/test/Volo.Abp.Core.Tests/Volo/Abp/AbpApplication_Initialize_Tests.cs @@ -156,6 +156,13 @@ public class AbpApplication_Initialize_Tests { application.ApplicationName.ShouldBe(applicationName); application.Services.GetApplicationName().ShouldBe(applicationName); + + application.Initialize(); + + application.ServiceProvider + .GetRequiredService() + .ApplicationName + .ShouldBe(applicationName); } } From ede078a4b1ed1067eb80eb476f638e3898293ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 17:42:32 +0300 Subject: [PATCH 29/70] Added extension method: HasSameExtraProperties --- .../Data/ExtraPropertyDictionaryExtensions.cs | 27 ++++++++++++++++++- .../Abp/Data/HasExtraPropertiesExtensions.cs | 11 ++++++++ .../HasExtraPropertiesExtensions_Tests.cs | 21 +++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs index b97b0056e9..d5de504afc 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/ExtraPropertyDictionaryExtensions.cs @@ -1,4 +1,5 @@ using System; +using JetBrains.Annotations; namespace Volo.Abp.Data; @@ -26,4 +27,28 @@ public static class ExtraPropertyDictionaryExtensions extraPropertyDictionary[key] = Enum.Parse(enumType, extraPropertyDictionary[key].ToString(), ignoreCase: true); return extraPropertyDictionary[key]; } -} + + public static bool HasSameItems( + [NotNull] this ExtraPropertyDictionary dictionary, + [NotNull] ExtraPropertyDictionary otherDictionary) + { + Check.NotNull(dictionary, nameof(dictionary)); + Check.NotNull(otherDictionary, nameof(otherDictionary)); + + if (dictionary.Count != otherDictionary.Count) + { + return false; + } + + foreach (var key in dictionary.Keys) + { + if (!otherDictionary.ContainsKey(key) || + dictionary[key]?.ToString() != otherDictionary[key]?.ToString()) + { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs index 0bd64d55f1..db543bb67f 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Linq; +using JetBrains.Annotations; using Volo.Abp.ObjectExtending; using Volo.Abp.Reflection; @@ -121,4 +122,14 @@ public static class HasExtraPropertiesExtensions source.RemoveProperty(property.Name); } } + + public static bool HasSameExtraProperties( + [NotNull] this IHasExtraProperties source, + [NotNull] IHasExtraProperties other) + { + Check.NotNull(source, nameof(source)); + Check.NotNull(other, nameof(other)); + + return source.ExtraProperties.HasSameItems(other.ExtraProperties); + } } diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs index 95e222e2c7..4ad99fee1e 100644 --- a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Testing/HasExtraPropertiesExtensions_Tests.cs @@ -45,4 +45,25 @@ public class HasExtraPropertiesExtensions_Tests city.SetProperty("DateTime?", DateTime.MinValue); city.GetProperty("DateTime?").ShouldBe(DateTime.MinValue); } + + [Fact] + public void HasSameExtraProperties_Tests() + { + var adana = new City(Guid.NewGuid(), "Adana"); + adana.SetProperty("IsHot", true); + + var antalya = new City(Guid.NewGuid(), "Antalya"); + antalya.SetProperty("IsHot", true); + + adana.HasSameExtraProperties(antalya).ShouldBeTrue(); + + adana.SetProperty("IsHot", false); + adana.HasSameExtraProperties(antalya).ShouldBeFalse(); + + adana.SetProperty("IsHot", true); + adana.HasSameExtraProperties(antalya).ShouldBeTrue(); + + adana.SetProperty("Population", 3_000_000); + adana.HasSameExtraProperties(antalya).ShouldBeFalse(); + } } From acd1660eca708c336547048161e5ffae3de4ff18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 18:42:34 +0300 Subject: [PATCH 30/70] Update changed permission groups --- .../IPermissionDefinitionSerializer.cs | 2 +- .../PermissionDefinitionSerializer.cs | 4 +- .../PermissionGroupDefinitionRecord.cs | 43 ++++++ .../PermissionManagementOptions.cs | 6 + .../StaticPermissionSaver.cs | 138 ++++++++++++++++-- .../PermissionDefinitionSerializer_Tests.cs | 35 ----- 6 files changed, 181 insertions(+), 47 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs index 799896a5d8..ce76afc10c 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs @@ -14,6 +14,6 @@ public interface IPermissionDefinitionSerializer Task SerializeAsync( PermissionGroupDefinition permissionGroup); - Task<(List, List)> + Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> SerializeAsync(IEnumerable permissionGroups); } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index bccfd65a7a..c7a8dac1bb 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -81,7 +81,7 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I } } - public async Task<(List, List)> + public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> SerializeAsync(IEnumerable permissionGroups) { var permissionGroupRecords = new List(); @@ -97,7 +97,7 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I } } - return (permissionGroupRecords, permissionRecords); + return (permissionGroupRecords.ToArray(), permissionRecords.ToArray()); } public Task DeserializeAsync(PermissionGroupDefinitionRecord permissionGroupRecord) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs index ff0c817ad2..c1f9656e2c 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs @@ -30,4 +30,47 @@ public class PermissionGroupDefinitionRecord : BasicAggregateRoot, IHasExt ExtraProperties = new ExtraPropertyDictionary(); this.SetDefaultsForExtraProperties(); } + + public bool HasSameData(PermissionGroupDefinitionRecord otherRecord) + { + if (Name != otherRecord.Name) + { + return false; + } + + if (DisplayName != otherRecord.DisplayName) + { + return false; + } + + if (!this.HasSameExtraProperties(otherRecord)) + { + return false; + } + + return true; + } + + public void Patch(PermissionGroupDefinitionRecord record) + { + if (Name != record.Name) + { + Name = record.Name; + } + + if (DisplayName != record.DisplayName) + { + DisplayName = record.DisplayName; + } + + if (!this.HasSameExtraProperties(record)) + { + this.ExtraProperties.Clear(); + + foreach (var property in record.ExtraProperties) + { + this.ExtraProperties.Add(property.Key, property.Value); + } + } + } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs index 15da755a33..55137878f3 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs @@ -8,10 +8,16 @@ public class PermissionManagementOptions public ITypeList ManagementProviders { get; } public Dictionary ProviderPolicies { get; } + + public HashSet DeletedPermissions { get; } + public HashSet DeletedPermissionGroups { get; } public PermissionManagementOptions() { ManagementProviders = new TypeList(); ProviderPolicies = new Dictionary(); + + DeletedPermissions = new HashSet(); + DeletedPermissionGroups = new HashSet(); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index c3b1e85866..c6ecfa2a2b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -1,7 +1,15 @@ +using System; using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; using Volo.Abp.Uow; namespace Volo.Abp.PermissionManagement; @@ -12,34 +20,146 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; } protected IPermissionDefinitionRecordRepository PermissionRepository { get; } protected IPermissionDefinitionSerializer PermissionSerializer { get; } - + protected IDistributedCache Cache { get; } + protected IApplicationNameAccessor ApplicationNameAccessor { get; } + public IAbpDistributedLock DistributedLock { get; } + public PermissionManagementOptions PermissionManagementOptions { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + public StaticPermissionSaver( IStaticPermissionDefinitionStore staticStore, IPermissionGroupDefinitionRecordRepository permissionGroupRepository, IPermissionDefinitionRecordRepository permissionRepository, - IPermissionDefinitionSerializer permissionSerializer) + IPermissionDefinitionSerializer permissionSerializer, + IDistributedCache cache, + IOptions cacheOptions, + IApplicationNameAccessor applicationNameAccessor, + IAbpDistributedLock distributedLock, + IOptions permissionManagementOptions) { StaticStore = staticStore; PermissionGroupRepository = permissionGroupRepository; PermissionRepository = permissionRepository; PermissionSerializer = permissionSerializer; + Cache = cache; + ApplicationNameAccessor = applicationNameAccessor; + DistributedLock = distributedLock; + PermissionManagementOptions = permissionManagementOptions.Value; + CacheOptions = cacheOptions.Value; } [UnitOfWork] public virtual async Task SaveAsync() { - // TODO: Save only changed permissions & groups - /* + get all groups & perms - * - compare and update or insert groups - * - get all permissions - * - compare and update or insert permissions - * - set in-memory cache using the latest group and permission data - */ + await using var handle = await DistributedLock.TryAcquireAsync(GetDistributedLockKey()); + + if (handle == null) + { + /* Another instance already did it */ + return; + } + + var cacheKey = GetCacheKey(); + var cachedHash = await Cache.GetStringAsync(cacheKey); var (permissionGroupRecords, permissionRecords) = await PermissionSerializer.SerializeAsync( await StaticStore.GetGroupsAsync() ); + + var currentHash = CalculateHash( + permissionGroupRecords, + permissionRecords, + PermissionManagementOptions.DeletedPermissionGroups, + PermissionManagementOptions.DeletedPermissions + ); + + if (cachedHash == currentHash) + { + return; + } + + await UpdateChangedGroupsAsync(permissionGroupRecords); + + await Cache.SetStringAsync( + cacheKey, + currentHash, + new DistributedCacheEntryOptions { + SlidingExpiration = TimeSpan.FromDays(2) + } + ); + } + + private async Task UpdateChangedGroupsAsync(PermissionGroupDefinitionRecord[] permissionGroupRecords) + { + var newRecords = new List(); + var changedRecords = new List(); + + var permissionGroupRecordsInDatabase = (await PermissionGroupRepository.GetListAsync()) + .ToDictionary(x => x.Name); + + foreach (var permissionGroupRecord in permissionGroupRecords) + { + var permissionGroupRecordInDatabase = permissionGroupRecordsInDatabase.GetOrDefault(permissionGroupRecord.Name); + if (permissionGroupRecordInDatabase == null) + { + /* New group */ + newRecords.Add(permissionGroupRecord); + continue; + } + + if (permissionGroupRecord.HasSameData(permissionGroupRecordInDatabase)) + { + /* Not changed */ + continue; + } + + /* Changed */ + permissionGroupRecordInDatabase.Patch(permissionGroupRecord); + changedRecords.Add(permissionGroupRecordInDatabase); + } + + /* Deleted */ + var deletedRecords = permissionGroupRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissionGroups.Contains(x.Name)) + .ToArray(); + + await PermissionGroupRepository.InsertManyAsync(newRecords); + await PermissionGroupRepository.UpdateManyAsync(changedRecords); + await PermissionGroupRepository.DeleteManyAsync(deletedRecords); + } + + private string GetDistributedLockKey() + { + return $"{ApplicationNameAccessor.ApplicationName}_AbpPermissionUpdateLock"; + } + + private string GetCacheKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionsHash"; + } + + private static string CalculateHash( + PermissionGroupDefinitionRecord[] permissionGroupRecords, + PermissionDefinitionRecord[] permissionRecords, + IEnumerable deletedPermissionGroups, + IEnumerable deletedPermissions) + { + var stringBuilder = new StringBuilder(); + + stringBuilder.Append("PermissionGroupRecords:"); + stringBuilder.AppendLine(JsonSerializer.Serialize(permissionGroupRecords)); + + stringBuilder.Append("PermissionRecords:"); + stringBuilder.AppendLine(JsonSerializer.Serialize(permissionRecords)); + + stringBuilder.Append("DeletedPermissionGroups:"); + stringBuilder.AppendLine(deletedPermissionGroups.JoinAsString(",")); + stringBuilder.Append("DeletedPermission:"); + stringBuilder.Append(deletedPermissions.JoinAsString(",")); + return stringBuilder + .ToString() + .ToMd5(); } } \ No newline at end of file diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index cac2892838..21f18cca1d 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -73,41 +73,6 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"GF\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]}]"); } - - [Fact(Skip = "Not implemented yet")] - public async Task Deserialize_Complex_Permission_Definition() - { - // Arrange - - var permissionRecord = new PermissionDefinitionRecord - { - Name = "Permission1", - GroupName = "Group1", - DisplayName = "Permission one", - Providers = "ProviderA,ProviderB", - IsEnabled = true, - MultiTenancySide = MultiTenancySides.Tenant, - StateCheckers = "[{\"T\":\"GF\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]}]" - }; - - // Act - - var permission = await _serializer.DeserializeAsync(permissionRecord); - - //Assert - - permission.Name.ShouldBe("Permission1"); - permission.DisplayName.ShouldBeOfType(); - permission.DisplayName.As().Value.ShouldBe("Permission one"); - permission.Parent.ShouldBeNull(); - permission.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); - permission.IsEnabled.ShouldBe(true); - permission.Providers.Count.ShouldBe(2); - permission.Providers.ShouldContain("ProviderA"); - permission.Providers.ShouldContain("ProviderB"); - permission.StateCheckers.Count.ShouldBe(1); - permission.StateCheckers[0].ShouldBeOfType>(); - } private static PermissionGroupDefinition CreatePermissionGroup1( IPermissionDefinitionContext context) From 6bfc492344f223a4965684c9b74b2e611f1f2ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 18:49:00 +0300 Subject: [PATCH 31/70] Implement UpdateChangedPermissionGroupsAsync. --- .../PermissionDefinitionRecord.cs | 103 ++++++++++++++++++ .../PermissionGroupDefinitionRecord.cs | 14 +-- .../StaticPermissionSaver.cs | 44 +++++++- 3 files changed, 152 insertions(+), 9 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs index f2a9173140..7421866869 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -61,4 +61,107 @@ public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraPro ExtraProperties = new ExtraPropertyDictionary(); this.SetDefaultsForExtraProperties(); } + + public bool HasSameData(PermissionDefinitionRecord otherRecord) + { + if (Name != otherRecord.Name) + { + return false; + } + + if (GroupName != otherRecord.GroupName) + { + return false; + } + + if (ParentName != otherRecord.ParentName) + { + return false; + } + + if (DisplayName != otherRecord.DisplayName) + { + return false; + } + + if (IsEnabled != otherRecord.IsEnabled) + { + return false; + } + + if (MultiTenancySide != otherRecord.MultiTenancySide) + { + return false; + } + + if (Providers != otherRecord.Providers) + { + return false; + } + + if (StateCheckers != otherRecord.StateCheckers) + { + return false; + } + + if (!this.HasSameExtraProperties(otherRecord)) + { + return false; + } + + return true; + } + + public void Patch(PermissionDefinitionRecord otherRecord) + { + if (Name != otherRecord.Name) + { + Name = otherRecord.Name; + } + + if (GroupName != otherRecord.GroupName) + { + GroupName = otherRecord.GroupName; + } + + if (ParentName != otherRecord.ParentName) + { + ParentName = otherRecord.ParentName; + } + + if (DisplayName != otherRecord.DisplayName) + { + DisplayName = otherRecord.DisplayName; + } + + if (IsEnabled != otherRecord.IsEnabled) + { + IsEnabled = otherRecord.IsEnabled; + } + + if (MultiTenancySide != otherRecord.MultiTenancySide) + { + MultiTenancySide = otherRecord.MultiTenancySide; + } + + if (Providers != otherRecord.Providers) + { + Providers = otherRecord.Providers; + } + + if (StateCheckers != otherRecord.StateCheckers) + { + StateCheckers = otherRecord.StateCheckers; + } + + if (!this.HasSameExtraProperties(otherRecord)) + { + this.ExtraProperties.Clear(); + + foreach (var property in otherRecord.ExtraProperties) + { + this.ExtraProperties.Add(property.Key, property.Value); + } + } + } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs index c1f9656e2c..7666b1ded8 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs @@ -51,23 +51,23 @@ public class PermissionGroupDefinitionRecord : BasicAggregateRoot, IHasExt return true; } - public void Patch(PermissionGroupDefinitionRecord record) + public void Patch(PermissionGroupDefinitionRecord otherRecord) { - if (Name != record.Name) + if (Name != otherRecord.Name) { - Name = record.Name; + Name = otherRecord.Name; } - if (DisplayName != record.DisplayName) + if (DisplayName != otherRecord.DisplayName) { - DisplayName = record.DisplayName; + DisplayName = otherRecord.DisplayName; } - if (!this.HasSameExtraProperties(record)) + if (!this.HasSameExtraProperties(otherRecord)) { this.ExtraProperties.Clear(); - foreach (var property in record.ExtraProperties) + foreach (var property in otherRecord.ExtraProperties) { this.ExtraProperties.Add(property.Key, property.Value); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index c6ecfa2a2b..94d332ccdb 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -78,7 +78,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc return; } - await UpdateChangedGroupsAsync(permissionGroupRecords); + await UpdateChangedPermissionGroupsAsync(permissionGroupRecords); + await UpdateChangedPermissionsAsync(permissionRecords); await Cache.SetStringAsync( cacheKey, @@ -89,7 +90,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc ); } - private async Task UpdateChangedGroupsAsync(PermissionGroupDefinitionRecord[] permissionGroupRecords) + private async Task UpdateChangedPermissionGroupsAsync(IEnumerable permissionGroupRecords) { var newRecords = new List(); var changedRecords = new List(); @@ -127,6 +128,45 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc await PermissionGroupRepository.UpdateManyAsync(changedRecords); await PermissionGroupRepository.DeleteManyAsync(deletedRecords); } + + private async Task UpdateChangedPermissionsAsync(IEnumerable permissionRecords) + { + var newRecords = new List(); + var changedRecords = new List(); + + var permissionRecordsInDatabase = (await PermissionRepository.GetListAsync()) + .ToDictionary(x => x.Name); + + foreach (var permissionRecord in permissionRecords) + { + var permissionRecordInDatabase = permissionRecordsInDatabase.GetOrDefault(permissionRecord.Name); + if (permissionRecordInDatabase == null) + { + /* New group */ + newRecords.Add(permissionRecord); + continue; + } + + if (permissionRecord.HasSameData(permissionRecordInDatabase)) + { + /* Not changed */ + continue; + } + + /* Changed */ + permissionRecordInDatabase.Patch(permissionRecord); + changedRecords.Add(permissionRecordInDatabase); + } + + /* Deleted */ + var deletedRecords = permissionRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissions.Contains(x.Name)) + .ToArray(); + + await PermissionRepository.InsertManyAsync(newRecords); + await PermissionRepository.UpdateManyAsync(changedRecords); + await PermissionRepository.DeleteManyAsync(deletedRecords); + } private string GetDistributedLockKey() { From 4375f5860f12246ea3c7c2a7cdaf2e01aa5a35ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Mon, 15 Aug 2022 18:56:28 +0300 Subject: [PATCH 32/70] Refactor StaticPermissionSaver --- .../StaticPermissionSaver.cs | 59 ++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index 94d332ccdb..a7e3497af6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -58,6 +58,11 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc /* Another instance already did it */ return; } + + /* NOTE: This can be further optimized by using 4 cache values for: + * Groups, permissions, deleted groups and deleted permissions. + * But the code would be more complex. + */ var cacheKey = GetCacheKey(); var cachedHash = await Cache.GetStringAsync(cacheKey); @@ -77,7 +82,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc { return; } - + await UpdateChangedPermissionGroupsAsync(permissionGroupRecords); await UpdateChangedPermissionsAsync(permissionRecords); @@ -85,7 +90,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc cacheKey, currentHash, new DistributedCacheEntryOptions { - SlidingExpiration = TimeSpan.FromDays(2) + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? } ); } @@ -120,13 +125,26 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc } /* Deleted */ - var deletedRecords = permissionGroupRecordsInDatabase.Values - .Where(x => PermissionManagementOptions.DeletedPermissionGroups.Contains(x.Name)) - .ToArray(); + var deletedRecords = PermissionManagementOptions.DeletedPermissionGroups.Any() + ? permissionGroupRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissionGroups.Contains(x.Name)) + .ToArray() + : Array.Empty(); + + if (newRecords.Any()) + { + await PermissionGroupRepository.InsertManyAsync(newRecords); + } - await PermissionGroupRepository.InsertManyAsync(newRecords); - await PermissionGroupRepository.UpdateManyAsync(changedRecords); - await PermissionGroupRepository.DeleteManyAsync(deletedRecords); + if (changedRecords.Any()) + { + await PermissionGroupRepository.UpdateManyAsync(changedRecords); + } + + if (deletedRecords.Any()) + { + await PermissionGroupRepository.DeleteManyAsync(deletedRecords); + } } private async Task UpdateChangedPermissionsAsync(IEnumerable permissionRecords) @@ -159,13 +177,26 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc } /* Deleted */ - var deletedRecords = permissionRecordsInDatabase.Values - .Where(x => PermissionManagementOptions.DeletedPermissions.Contains(x.Name)) - .ToArray(); + var deletedRecords = PermissionManagementOptions.DeletedPermissions.Any() + ? permissionRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissions.Contains(x.Name)) + .ToArray() + : Array.Empty(); - await PermissionRepository.InsertManyAsync(newRecords); - await PermissionRepository.UpdateManyAsync(changedRecords); - await PermissionRepository.DeleteManyAsync(deletedRecords); + if (newRecords.Any()) + { + await PermissionRepository.InsertManyAsync(newRecords); + } + + if (changedRecords.Any()) + { + await PermissionRepository.UpdateManyAsync(changedRecords); + } + + if (deletedRecords.Any()) + { + await PermissionRepository.DeleteManyAsync(deletedRecords); + } } private string GetDistributedLockKey() From 5db75833afe9076e838c43f25bbe5d4019069bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 07:55:20 +0300 Subject: [PATCH 33/70] complete initial DynamicPermissionDefinitionStore --- .../DynamicPermissionDefinitionStore.cs | 64 ++++++++++++++---- ...PermissionDefinitionStoreInMemoryCache.cs} | 67 +++++++++---------- ...cPermissionDefinitionStoreInMemoryCache.cs | 23 +++++++ .../StaticPermissionSaver.cs | 23 +++++-- 4 files changed, 124 insertions(+), 53 deletions(-) rename modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/{DynamicPermissionDefinitionStoreCache.cs => DynamicPermissionDefinitionStoreInMemoryCache.cs} (73%) create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index 966fca75ae..20d95da692 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -1,8 +1,11 @@ -using System; using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.PermissionManagement; @@ -12,35 +15,72 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; } protected IPermissionDefinitionRecordRepository PermissionRepository { get; } protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; } - + protected IDynamicPermissionDefinitionStoreInMemoryCache StoreCache { get; } + protected IDistributedCache DistributedCache { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + public DynamicPermissionDefinitionStore( IPermissionGroupDefinitionRecordRepository permissionGroupRepository, IPermissionDefinitionRecordRepository permissionRepository, - IPermissionDefinitionSerializer permissionDefinitionSerializer) + IPermissionDefinitionSerializer permissionDefinitionSerializer, + IDynamicPermissionDefinitionStoreInMemoryCache storeCache, + IDistributedCache distributedCache, + IOptions cacheOptions) { PermissionGroupRepository = permissionGroupRepository; PermissionRepository = permissionRepository; PermissionDefinitionSerializer = permissionDefinitionSerializer; + StoreCache = storeCache; + DistributedCache = distributedCache; + CacheOptions = cacheOptions.Value; } public virtual async Task GetOrNullAsync(string name) { - var permissionRecord = await PermissionRepository.FindByNameAsync(name); - if (permissionRecord == null) - { - return null; - } - - throw new NotImplementedException(); + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissionOrNull(name); } public virtual async Task> GetPermissionsAsync() { - throw new NotImplementedException(); + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissions(); } public virtual async Task> GetGroupsAsync() { - throw new NotImplementedException(); + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetGroups(); + } + + private async Task EnsureCacheIsUptoDateAsync() + { + /* TODO: Optimization note: May not check for a few seconds + * It is acceptable to get changes a few seconds after the last time the cache was updated. + */ + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + var cacheKey = GetCacheKey(); + + var stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); + + if (StoreCache.CacheStamp == stampInDistributedCache) + { + return; + } + + var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); + var permissionRecords = await PermissionRepository.GetListAsync(); + + await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); + + StoreCache.CacheStamp = stampInDistributedCache; + } + } + + private string GetCacheKey() + { + return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs similarity index 73% rename from modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs rename to modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs index 002121aeb3..d807de9371 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; @@ -9,27 +10,32 @@ using Volo.Abp.SimpleStateChecking; namespace Volo.Abp.PermissionManagement; -//TODO: Extract interface -public class DynamicPermissionDefinitionStoreCache : ISingletonDependency +public class DynamicPermissionDefinitionStoreInMemoryCache : + IDynamicPermissionDefinitionStoreInMemoryCache, + ISingletonDependency { public string CacheStamp { get; set; } protected IDictionary PermissionGroupDefinitions { get; } - protected IDictionary PermissionDefinitions { get; } protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } - public DynamicPermissionDefinitionStoreCache(ISimpleStateCheckerSerializer stateCheckerSerializer) + public DynamicPermissionDefinitionStoreInMemoryCache(ISimpleStateCheckerSerializer stateCheckerSerializer) { StateCheckerSerializer = stateCheckerSerializer; PermissionGroupDefinitions = new Dictionary(); PermissionDefinitions = new Dictionary(); } + public SemaphoreSlim SyncSemaphore { get; } = new(1, 1); + public Task FillAsync( List permissionGroupRecords, List permissionRecords) { + PermissionGroupDefinitions.Clear(); + PermissionDefinitions.Clear(); + var context = new PermissionDefinitionContext(null); foreach (var permissionGroupRecord in permissionGroupRecords) @@ -38,6 +44,8 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency permissionGroupRecord.Name, new FixedLocalizableString(permissionGroupRecord.DisplayName) //TODO: Consider localization ); + + PermissionGroupDefinitions[permissionGroup.Name] = permissionGroup; foreach (var property in permissionGroupRecord.ExtraProperties) { @@ -52,10 +60,25 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency AddPermissionRecursively(permissionGroup, permissionRecord, permissionRecords); } } - + return Task.CompletedTask; } + public PermissionDefinition GetPermissionOrNull(string name) + { + return PermissionDefinitions.GetOrDefault(name); + } + + public IReadOnlyList GetPermissions() + { + return PermissionDefinitions.Values.ToList(); + } + + public IReadOnlyList GetGroups() + { + return PermissionGroupDefinitions.Values.ToList(); + } + private void AddPermissionRecursively(ICanAddChildPermission permissionContainer, PermissionDefinitionRecord permissionRecord, List allPermissionRecords) @@ -66,6 +89,8 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency permissionRecord.MultiTenancySide, permissionRecord.IsEnabled ); + + PermissionDefinitions[permission.Name] = permission; if (!permissionRecord.Providers.IsNullOrWhiteSpace()) { @@ -91,36 +116,4 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency AddPermissionRecursively(permission, subPermission, allPermissionRecords); } } - - protected virtual Dictionary CreatePermissionDefinitions() - { - var permissions = new Dictionary(); - - foreach (var groupDefinition in PermissionGroupDefinitions.Values) - { - foreach (var permission in groupDefinition.Permissions) - { - AddPermissionToDictionaryRecursively(permissions, permission); - } - } - - return permissions; - } - - protected virtual void AddPermissionToDictionaryRecursively( - Dictionary permissions, - PermissionDefinition permission) - { - if (permissions.ContainsKey(permission.Name)) - { - throw new AbpException("Duplicate permission name: " + permission.Name); - } - - permissions[permission.Name] = permission; - - foreach (var child in permission.Children) - { - AddPermissionToDictionaryRecursively(permissions, child); - } - } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs new file mode 100644 index 0000000000..e6a1da3b79 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.PermissionManagement; + +public interface IDynamicPermissionDefinitionStoreInMemoryCache +{ + string CacheStamp { get; set; } + + SemaphoreSlim SyncSemaphore { get; } + + Task FillAsync( + List permissionGroupRecords, + List permissionRecords); + + PermissionDefinition GetPermissionOrNull(string name); + + IReadOnlyList GetPermissions(); + + IReadOnlyList GetGroups(); +} \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index a7e3497af6..8293bdc071 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -22,8 +22,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc protected IPermissionDefinitionSerializer PermissionSerializer { get; } protected IDistributedCache Cache { get; } protected IApplicationNameAccessor ApplicationNameAccessor { get; } - public IAbpDistributedLock DistributedLock { get; } - public PermissionManagementOptions PermissionManagementOptions { get; } + protected IAbpDistributedLock DistributedLock { get; } + protected PermissionManagementOptions PermissionManagementOptions { get; } protected AbpDistributedCacheOptions CacheOptions { get; } public StaticPermissionSaver( @@ -51,6 +51,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc [UnitOfWork] public virtual async Task SaveAsync() { + /* TODO: We may double check and lock for optimization + */ await using var handle = await DistributedLock.TryAcquireAsync(GetDistributedLockKey()); if (handle == null) @@ -64,7 +66,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc * But the code would be more complex. */ - var cacheKey = GetCacheKey(); + var cacheKey = GetApplicationHashCacheKey(); var cachedHash = await Cache.GetStringAsync(cacheKey); var (permissionGroupRecords, permissionRecords) = await PermissionSerializer.SerializeAsync( @@ -93,6 +95,14 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? } ); + + await Cache.SetStringAsync( + GetCommonStampCacheKey(), + Guid.NewGuid().ToString(), + new DistributedCacheEntryOptions { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + } + ); } private async Task UpdateChangedPermissionGroupsAsync(IEnumerable permissionGroupRecords) @@ -204,10 +214,15 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc return $"{ApplicationNameAccessor.ApplicationName}_AbpPermissionUpdateLock"; } - private string GetCacheKey() + private string GetApplicationHashCacheKey() { return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionsHash"; } + + private string GetCommonStampCacheKey() + { + return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; + } private static string CalculateHash( PermissionGroupDefinitionRecord[] permissionGroupRecords, From 0c0dac1f147e739f001cc92777c1e359f741adfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 08:02:50 +0300 Subject: [PATCH 34/70] Update DynamicPermissionDefinitionStoreInMemoryCache.cs --- .../DynamicPermissionDefinitionStoreInMemoryCache.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs index d807de9371..fc35087e06 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -20,6 +20,8 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : protected IDictionary PermissionDefinitions { get; } protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } + public SemaphoreSlim SyncSemaphore { get; } = new(1, 1); + public DynamicPermissionDefinitionStoreInMemoryCache(ISimpleStateCheckerSerializer stateCheckerSerializer) { StateCheckerSerializer = stateCheckerSerializer; @@ -27,8 +29,6 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : PermissionDefinitions = new Dictionary(); } - public SemaphoreSlim SyncSemaphore { get; } = new(1, 1); - public Task FillAsync( List permissionGroupRecords, List permissionRecords) From 3aef1709dfb687dd5381b8a2e16173f3a9a5f2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 08:13:19 +0300 Subject: [PATCH 35/70] Remove usage of multiTenancySide on AddGroup --- .../FeatureManagement/FeaturePermissionDefinitionProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeaturePermissionDefinitionProvider.cs b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeaturePermissionDefinitionProvider.cs index d2b0707058..483891959d 100644 --- a/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeaturePermissionDefinitionProvider.cs +++ b/modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/FeaturePermissionDefinitionProvider.cs @@ -11,8 +11,7 @@ public class FeaturePermissionDefinitionProvider : PermissionDefinitionProvider { var featureManagementGroup = context.AddGroup( FeatureManagementPermissions.GroupName, - L("Permission:FeatureManagement"), - multiTenancySide: MultiTenancySides.Host); + L("Permission:FeatureManagement")); featureManagementGroup.AddPermission( FeatureManagementPermissions.ManageHostFeatures, From b71b68bb8e6036d103cc497bdc56f34f81cfe0df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 08:44:42 +0300 Subject: [PATCH 36/70] Providers and StateCheckers can be null. --- .../AbpPermissionManagementDbContextModelBuilderExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs index d8b3dd4362..c901cbeb7f 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/AbpPermissionManagementDbContextModelBuilderExtensions.cs @@ -51,8 +51,8 @@ public static class AbpPermissionManagementDbContextModelBuilderExtensions b.Property(x => x.Name).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength).IsRequired(); b.Property(x => x.ParentName).HasMaxLength(PermissionDefinitionRecordConsts.MaxNameLength); b.Property(x => x.DisplayName).HasMaxLength(PermissionDefinitionRecordConsts.MaxDisplayNameLength).IsRequired(); - b.Property(x => x.Providers).HasMaxLength(PermissionDefinitionRecordConsts.MaxProvidersLength).IsRequired(); - b.Property(x => x.StateCheckers).HasMaxLength(PermissionDefinitionRecordConsts.MaxStateCheckersLength).IsRequired(); + b.Property(x => x.Providers).HasMaxLength(PermissionDefinitionRecordConsts.MaxProvidersLength); + b.Property(x => x.StateCheckers).HasMaxLength(PermissionDefinitionRecordConsts.MaxStateCheckersLength); b.HasIndex(x => new { x.Name }).IsUnique(); b.HasIndex(x => new { x.GroupName }); From 83904bb0e51351f31ac63e1641a5c8edd14e1185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 09:12:34 +0300 Subject: [PATCH 37/70] Return null for empty serializer list. --- .../SimpleStateCheckerSerializerExtensions.cs | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs index c5fbb824b3..3c852fc901 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Text.Json.Nodes; namespace Volo.Abp.SimpleStateChecking; @@ -18,23 +17,25 @@ public static class SimpleStateCheckerSerializerExtensions case 0: return null; case 1: - return $"[{serializer.Serialize(stateCheckers.Single())}]"; + var serializedChecker = serializer.Serialize(stateCheckers.Single()); + return serializedChecker != null + ? $"[{serializedChecker}]" + : null; default: - var stringBuilder = new StringBuilder("["); + var serializedCheckers = new List(stateCheckers.Count); - for (var i = 0; i < stateCheckers.Count; i++) + foreach (var stateChecker in stateCheckers) { - if (i > 0) + var serialized = serializer.Serialize(stateChecker); + if (serialized != null) { - stringBuilder.Append(","); + serializedCheckers.Add(serialized); } - - stringBuilder.Append(serializer.Serialize(stateCheckers[i])); } - stringBuilder.Append("]"); - - return stringBuilder.ToString(); + return serializedCheckers.Any() + ? $"[{serializedCheckers.JoinAsString(",")}]" + : null; } } @@ -62,10 +63,16 @@ public static class SimpleStateCheckerSerializerExtensions throw new AbpException("JSON value is not an array of objects: " + value); } - return new[] { serializer.Deserialize(jsonObject) }; + var checker = serializer.Deserialize(jsonObject); + if (checker == null) + { + return Array.Empty>(); + } + + return new[] { checker }; } - var checkers = new ISimpleStateChecker[array.Count]; + var checkers = new List>(); for (var i = 0; i < array.Count; i++) { @@ -77,6 +84,6 @@ public static class SimpleStateCheckerSerializerExtensions checkers[i] = serializer.Deserialize(jsonObject); } - return checkers; + return checkers.Where(x => x != null).ToArray(); } } \ No newline at end of file From 14cab94779e3e869d33fa69b05f0a392b89103b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 09:44:29 +0300 Subject: [PATCH 38/70] Add options to enable/disable dynamic permissions. --- .../AbpPermissionManagementDomainModule.cs | 17 +++++++++++++-- .../DynamicPermissionDefinitionStore.cs | 21 ++++++++++++++++++- .../PermissionManagementOptions.cs | 11 ++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index de5c7a0559..f452035163 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Volo.Abp.Authorization; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; @@ -19,6 +20,18 @@ namespace Volo.Abp.PermissionManagement; public class AbpPermissionManagementDomainModule : AbpModule { public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + if (context + .ServiceProvider + .GetRequiredService>() + .Value + .SaveStaticPermissionsToDatabase) + { + SaveStaticPermissionsToDatabase(context); + } + } + + private static void SaveStaticPermissionsToDatabase(ApplicationInitializationContext context) { Task.Run(async () => { @@ -26,7 +39,7 @@ public class AbpPermissionManagementDomainModule : AbpModule .ServiceProvider .GetRequiredService() .CreateScope(); - + try { await scope @@ -37,7 +50,7 @@ public class AbpPermissionManagementDomainModule : AbpModule catch (Exception ex) { //TODO: We should retry until it's successful! - + scope.ServiceProvider .GetService>() .LogException(ex); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index 20d95da692..2186ae56cf 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; @@ -17,6 +18,7 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; } protected IDynamicPermissionDefinitionStoreInMemoryCache StoreCache { get; } protected IDistributedCache DistributedCache { get; } + public PermissionManagementOptions PermissionManagementOptions { get; } protected AbpDistributedCacheOptions CacheOptions { get; } public DynamicPermissionDefinitionStore( @@ -25,30 +27,47 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor IPermissionDefinitionSerializer permissionDefinitionSerializer, IDynamicPermissionDefinitionStoreInMemoryCache storeCache, IDistributedCache distributedCache, - IOptions cacheOptions) + IOptions cacheOptions, + IOptions permissionManagementOptions) { PermissionGroupRepository = permissionGroupRepository; PermissionRepository = permissionRepository; PermissionDefinitionSerializer = permissionDefinitionSerializer; StoreCache = storeCache; DistributedCache = distributedCache; + PermissionManagementOptions = permissionManagementOptions.Value; CacheOptions = cacheOptions.Value; } public virtual async Task GetOrNullAsync(string name) { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return null; + } + await EnsureCacheIsUptoDateAsync(); return StoreCache.GetPermissionOrNull(name); } public virtual async Task> GetPermissionsAsync() { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return Array.Empty(); + } + await EnsureCacheIsUptoDateAsync(); return StoreCache.GetPermissions(); } public virtual async Task> GetGroupsAsync() { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return Array.Empty(); + } + await EnsureCacheIsUptoDateAsync(); return StoreCache.GetGroups(); } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs index 55137878f3..2109941a27 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs @@ -10,7 +10,18 @@ public class PermissionManagementOptions public Dictionary ProviderPolicies { get; } public HashSet DeletedPermissions { get; } + public HashSet DeletedPermissionGroups { get; } + + /// + /// Default: true. + /// + public bool SaveStaticPermissionsToDatabase { get; set; } = true; + + /// + /// Default: false. + /// + public bool IsDynamicPermissionStoreEnabled { get; set; } public PermissionManagementOptions() { From eb2313437839ef70406d340c81136b953303fd02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 11:15:32 +0300 Subject: [PATCH 39/70] Remove permissions in a removed group --- .../StaticPermissionSaver.cs | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index 8293bdc071..ed55e6f50e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -105,7 +105,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc ); } - private async Task UpdateChangedPermissionGroupsAsync(IEnumerable permissionGroupRecords) + private async Task UpdateChangedPermissionGroupsAsync( + IEnumerable permissionGroupRecords) { var newRecords = new List(); var changedRecords = new List(); @@ -157,7 +158,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc } } - private async Task UpdateChangedPermissionsAsync(IEnumerable permissionRecords) + private async Task UpdateChangedPermissionsAsync( + IEnumerable permissionRecords) { var newRecords = new List(); var changedRecords = new List(); @@ -187,11 +189,23 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc } /* Deleted */ - var deletedRecords = PermissionManagementOptions.DeletedPermissions.Any() - ? permissionRecordsInDatabase.Values - .Where(x => PermissionManagementOptions.DeletedPermissions.Contains(x.Name)) - .ToArray() - : Array.Empty(); + var deletedRecords = new List(); + + if (PermissionManagementOptions.DeletedPermissions.Any()) + { + deletedRecords.AddRange( + permissionRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissions.Contains(x.Name)) + ); + } + + if (PermissionManagementOptions.DeletedPermissionGroups.Any()) + { + deletedRecords.AddIfNotContains( + permissionRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissionGroups.Contains(x.GroupName)) + ); + } if (newRecords.Any()) { From 12fb2d282f70aefbf89c5ecf490415071af92c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 11:23:31 +0300 Subject: [PATCH 40/70] Fix DynamicPermissionDefinitionStoreInMemoryCache --- .../DynamicPermissionDefinitionStoreInMemoryCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs index fc35087e06..4e567aadea 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -55,7 +55,7 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : var permissionRecordsInThisGroup = permissionRecords .Where(p => p.GroupName == permissionGroup.Name); - foreach (var permissionRecord in permissionRecordsInThisGroup) + foreach (var permissionRecord in permissionRecordsInThisGroup.Where(x => x.ParentName == null)) { AddPermissionRecursively(permissionGroup, permissionRecord, permissionRecords); } From 5c22e9239a75914c7e03d2401ea8e2b4b84d065c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 11:31:25 +0300 Subject: [PATCH 41/70] Fix PermissionDefinitionManager --- .../Permissions/PermissionDefinitionManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index 27c963fb5d..de24ff59c5 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs @@ -30,12 +30,12 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransi return permission; } - public virtual Task GetOrNullAsync(string name) + public virtual async Task GetOrNullAsync(string name) { Check.NotNull(name, nameof(name)); - return _staticStore.GetOrNullAsync(name) ?? - _dynamicStore.GetOrNullAsync(name); + return await _staticStore.GetOrNullAsync(name) ?? + await _dynamicStore.GetOrNullAsync(name); } public virtual async Task> GetPermissionsAsync() From 9d73add9ed65a6307d815ad7a9c89cdacb551999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 11:53:51 +0300 Subject: [PATCH 42/70] Use a common distributed lock while updating permissions Because different applications may try to change the same permissions (when permissions are located in a shared project). --- .../StaticPermissionSaver.cs | 59 +++++++++++++------ 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index ed55e6f50e..f3f8674755 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -53,11 +53,10 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc { /* TODO: We may double check and lock for optimization */ - await using var handle = await DistributedLock.TryAcquireAsync(GetDistributedLockKey()); - - if (handle == null) + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync(GetApplicationDistributedLockKey()); + if (applicationLockHandle == null) { - /* Another instance already did it */ + /* Another application instance is already doing it */ return; } @@ -84,28 +83,41 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc { return; } - - await UpdateChangedPermissionGroupsAsync(permissionGroupRecords); - await UpdateChangedPermissionsAsync(permissionRecords); - await Cache.SetStringAsync( - cacheKey, - currentHash, - new DistributedCacheEntryOptions { - SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + await using (var commonLockHandle = await DistributedLock + .TryAcquireAsync(GetCommonDistributedLockKey(), TimeSpan.FromMinutes(5))) + { + if (commonLockHandle == null) + { + /* It will re-try */ + throw new AbpException("Could not acquire distributed lock for saving static permissions!"); } - ); + + var hasChangesInGroups = await UpdateChangedPermissionGroupsAsync(permissionGroupRecords); + var hasChangesInPermissions = await UpdateChangedPermissionsAsync(permissionRecords); + + if (hasChangesInGroups ||hasChangesInPermissions) + { + await Cache.SetStringAsync( + GetCommonStampCacheKey(), + Guid.NewGuid().ToString(), + new DistributedCacheEntryOptions { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + } + ); + } + } await Cache.SetStringAsync( - GetCommonStampCacheKey(), - Guid.NewGuid().ToString(), + cacheKey, + currentHash, new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? } ); } - private async Task UpdateChangedPermissionGroupsAsync( + private async Task UpdateChangedPermissionGroupsAsync( IEnumerable permissionGroupRecords) { var newRecords = new List(); @@ -156,9 +168,11 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc { await PermissionGroupRepository.DeleteManyAsync(deletedRecords); } + + return newRecords.Any() || changedRecords.Any() || deletedRecords.Any(); } - private async Task UpdateChangedPermissionsAsync( + private async Task UpdateChangedPermissionsAsync( IEnumerable permissionRecords) { var newRecords = new List(); @@ -221,11 +235,18 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc { await PermissionRepository.DeleteManyAsync(deletedRecords); } + + return newRecords.Any() || changedRecords.Any() || deletedRecords.Any(); + } + + private string GetApplicationDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionUpdateLock"; } - private string GetDistributedLockKey() + private string GetCommonDistributedLockKey() { - return $"{ApplicationNameAccessor.ApplicationName}_AbpPermissionUpdateLock"; + return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; } private string GetApplicationHashCacheKey() From 7691008c6ae7067fe22b46f787f9ba27c87fc374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 16 Aug 2022 11:56:29 +0300 Subject: [PATCH 43/70] Update AbpPermissionManagementDomainModule.cs --- .../AbpPermissionManagementDomainModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index f452035163..f18781e36a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -19,7 +19,7 @@ namespace Volo.Abp.PermissionManagement; [DependsOn(typeof(AbpJsonModule))] public class AbpPermissionManagementDomainModule : AbpModule { - public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) { if (context .ServiceProvider @@ -29,6 +29,8 @@ public class AbpPermissionManagementDomainModule : AbpModule { SaveStaticPermissionsToDatabase(context); } + + return Task.CompletedTask; } private static void SaveStaticPermissionsToDatabase(ApplicationInitializationContext context) From 6d95b87f34c89e9f542ea5e923e5942371abc23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 17 Aug 2022 18:15:36 +0300 Subject: [PATCH 44/70] Handle initial null situation for permission definition cache stamp --- .../DynamicPermissionDefinitionStore.cs | 76 ++++++++++++++++--- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index 2186ae56cf..0e8b28d38e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; using Volo.Abp.Threading; namespace Volo.Abp.PermissionManagement; @@ -18,6 +19,7 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; } protected IDynamicPermissionDefinitionStoreInMemoryCache StoreCache { get; } protected IDistributedCache DistributedCache { get; } + protected IAbpDistributedLock DistributedLock { get; } public PermissionManagementOptions PermissionManagementOptions { get; } protected AbpDistributedCacheOptions CacheOptions { get; } @@ -28,13 +30,15 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor IDynamicPermissionDefinitionStoreInMemoryCache storeCache, IDistributedCache distributedCache, IOptions cacheOptions, - IOptions permissionManagementOptions) + IOptions permissionManagementOptions, + IAbpDistributedLock distributedLock) { PermissionGroupRepository = permissionGroupRepository; PermissionRepository = permissionRepository; PermissionDefinitionSerializer = permissionDefinitionSerializer; StoreCache = storeCache; DistributedCache = distributedCache; + DistributedLock = distributedLock; PermissionManagementOptions = permissionManagementOptions.Value; CacheOptions = cacheOptions.Value; } @@ -80,26 +84,76 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor using (await StoreCache.SyncSemaphore.LockAsync()) { - var cacheKey = GetCacheKey(); - - var stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); - - if (StoreCache.CacheStamp == stampInDistributedCache) + var stampInDistributedCache = await GetOrSetStampInDistributedCache(); + + if (stampInDistributedCache == StoreCache.CacheStamp) { return; } - var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); - var permissionRecords = await PermissionRepository.GetListAsync(); - - await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); + await UpdateInMemoryStoreCache(); StoreCache.CacheStamp = stampInDistributedCache; } } - private string GetCacheKey() + private async Task UpdateInMemoryStoreCache() + { + var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); + var permissionRecords = await PermissionRepository.GetListAsync(); + + await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); + } + + private async Task GetOrSetStampInDistributedCache() + { + var cacheKey = GetCommonStampCacheKey(); + + var stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); + if (stampInDistributedCache != null) + { + return stampInDistributedCache; + } + + await using (var commonLockHandle = await DistributedLock + .TryAcquireAsync(GetCommonDistributedLockKey(), TimeSpan.FromMinutes(2))) + { + if (commonLockHandle == null) + { + /* This request will fail */ + throw new AbpException( + "Could not acquire distributed lock for permission definition common stamp check!" + ); + } + + stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); + if (stampInDistributedCache != null) + { + return stampInDistributedCache; + } + + stampInDistributedCache = Guid.NewGuid().ToString(); + + await DistributedCache.SetStringAsync( + cacheKey, + stampInDistributedCache, + new DistributedCacheEntryOptions + { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + } + ); + } + + return stampInDistributedCache; + } + + private string GetCommonStampCacheKey() { return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; } + + private string GetCommonDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; + } } \ No newline at end of file From bc4133ad1b23468d0cf5e54c4e1be8c75e7a5607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 17 Aug 2022 18:33:12 +0300 Subject: [PATCH 45/70] Ignore Id of permission record entities on Json serialization --- .../PermissionManagement/PermissionDefinitionRecord.cs | 8 ++++++++ .../PermissionGroupDefinitionRecord.cs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs index 7421866869..2ba9ffa26a 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -1,4 +1,5 @@ using System; +using System.Text.Json.Serialization; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; @@ -7,6 +8,13 @@ namespace Volo.Abp.PermissionManagement; public class PermissionDefinitionRecord : BasicAggregateRoot, IHasExtraProperties { + /* Ignoring Id because it is different whenever we create an instance of + * this class, and we are using Json Serialize, than Hash to understand + * if permission definitions have changed (in StaticPermissionSaver.CalculateHash()). + */ + [JsonIgnore] + public override Guid Id { get; protected set; } + public string GroupName { get; set; } public string Name { get; set; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs index 7666b1ded8..f93bf57e21 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs @@ -1,4 +1,5 @@ using System; +using System.Text.Json.Serialization; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; @@ -6,6 +7,13 @@ namespace Volo.Abp.PermissionManagement; public class PermissionGroupDefinitionRecord : BasicAggregateRoot, IHasExtraProperties { + /* Ignoring Id because it is different whenever we create an instance of + * this class, and we are using Json Serialize, than Hash to understand + * if permission definitions have changed (in StaticPermissionSaver.CalculateHash()). + */ + [JsonIgnore] + public override Guid Id { get; protected set; } + public string Name { get; set; } public string DisplayName { get; set; } From 0389c17513450b821bbe6c37e5eab789eb41c915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 18 Aug 2022 08:02:07 +0300 Subject: [PATCH 46/70] Retry on failure in SaveStaticPermissionsToDatabase --- ...olo.Abp.PermissionManagement.Domain.csproj | 4 ++ .../AbpPermissionManagementDomainModule.cs | 45 ++++++++++++------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj index d9cc5a058f..39ec0e9763 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj @@ -23,4 +23,8 @@ + + + + diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index f18781e36a..ac0ddd8b1c 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Polly; using Volo.Abp.Authorization; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; @@ -35,28 +36,40 @@ public class AbpPermissionManagementDomainModule : AbpModule private static void SaveStaticPermissionsToDatabase(ApplicationInitializationContext context) { + var rootServiceProvider = context.ServiceProvider.GetRequiredService(); + Task.Run(async () => { - using var scope = context - .ServiceProvider - .GetRequiredService() - .CreateScope(); + using var scope = rootServiceProvider.CreateScope(); try { - await scope - .ServiceProvider - .GetRequiredService() - .SaveAsync(); - } - catch (Exception ex) - { - //TODO: We should retry until it's successful! - - scope.ServiceProvider - .GetService>() - .LogException(ex); + await Policy + .Handle() + .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) + .ExecuteAsync(async () => + { + try + { + // ReSharper disable once AccessToDisposedClosure + await scope + .ServiceProvider + .GetRequiredService() + .SaveAsync(); + } + catch (Exception ex) + { + // ReSharper disable once AccessToDisposedClosure + scope.ServiceProvider + .GetService>()? + .LogException(ex); + + throw; // Polly will catch it + } + }); } + // ReSharper disable once EmptyGeneralCatchClause (No need to log since it is logged above) + catch { } }); } } \ No newline at end of file From 7897fa0dfb4c6ad641900af7d50c69b6f4a7ebf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 18 Aug 2022 08:46:13 +0300 Subject: [PATCH 47/70] Implemented AuthenticatedSimpleStateCheckerSerializerContributor. --- ...SimpleStateCheckerSerializerContributor.cs | 36 ++++++++++++++++ ...StateCheckerSerializerContributor_Tests.cs | 41 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs create mode 100644 framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..97b3ae9b0f --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.Authorization.Permissions; + +public class AuthenticatedSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireAuthenticatedSimpleStateChecker requireAuthenticatedSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = "A" + }; + + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize(JsonObject jsonObject) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != "A") + { + return null; + } + + return new RequireAuthenticatedSimpleStateChecker(); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs new file mode 100644 index 0000000000..b6ae8bace4 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Shouldly; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.SimpleStateChecking; +using Xunit; + +namespace Volo.Abp.Authorization; + +public class AuthenticatedSimpleStateCheckerSerializerContributor_Tests +{ + [Fact] + public void Should_Serialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new AuthenticatedSimpleStateCheckerSerializerContributor(); + + var result = serializer.SerializeToJson( + new RequireAuthenticatedSimpleStateChecker() + ); + + result.ShouldBe("{\"T\":\"A\"}"); + } + + [Fact] + public void Should_Deserialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new AuthenticatedSimpleStateCheckerSerializerContributor(); + + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"A\"}"); + var checker = serializer.Deserialize(jsonObject); + + checker.ShouldBeOfType>(); + var globalFeaturesSimpleStateChecker = checker as RequireAuthenticatedSimpleStateChecker; + globalFeaturesSimpleStateChecker.ShouldNotBeNull(); + } + + private class MyState : IHasSimpleStateCheckers + { + public List> StateCheckers { get; } = new(); + } +} \ No newline at end of file From 7cb33a57f369dc7b4eaacc0d45d7cebc2a3996df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Thu, 18 Aug 2022 08:57:04 +0300 Subject: [PATCH 48/70] Added FeaturesSimpleStateCheckerSerializerContributor Also refactored other contributors and tests --- ...SimpleStateCheckerSerializerContributor.cs | 6 +- ...SimpleStateCheckerSerializerContributor.cs | 56 +++++++++++++++++++ .../RequireFeaturesSimpleStateChecker.cs | 10 ++-- ...SimpleStateCheckerSerializerContributor.cs | 6 +- ...tateCheckerSerializerContributor_Tests.cs} | 0 ...StateCheckerSerializerContributor_Tests.cs | 46 +++++++++++++++ ...StateCheckerSerializerContributor_Tests.cs | 4 +- 7 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs rename framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/{GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs => AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs} (100%) create mode 100644 framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs index 97b3ae9b0f..cb52f5f7ac 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs @@ -8,6 +8,8 @@ public class AuthenticatedSimpleStateCheckerSerializerContributor : ISimpleStateCheckerSerializerContributor, ISingletonDependency { + public const string CheckerShortName = "A"; + public string SerializeToJson(ISimpleStateChecker checker) where TState : IHasSimpleStateCheckers { @@ -17,7 +19,7 @@ public class AuthenticatedSimpleStateCheckerSerializerContributor : } var jsonObject = new JsonObject { - ["T"] = "A" + ["T"] = CheckerShortName }; return jsonObject.ToJsonString(); @@ -26,7 +28,7 @@ public class AuthenticatedSimpleStateCheckerSerializerContributor : public ISimpleStateChecker Deserialize(JsonObject jsonObject) where TState : IHasSimpleStateCheckers { - if (jsonObject["T"]?.ToString() != "A") + if (jsonObject["T"]?.ToString() != CheckerShortName) { return null; } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..7510cb4a24 --- /dev/null +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,56 @@ +using System.Linq; +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.Features; + +public class FeaturesSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "F"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireFeaturesSimpleStateChecker featuresSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName, + ["A"] = featuresSimpleStateChecker.RequiresAll + }; + + var nameArray = new JsonArray(); + foreach (var featureName in featuresSimpleStateChecker.FeatureNames) + { + nameArray.Add(featureName); + } + + jsonObject["N"] = nameArray; + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize(JsonObject jsonObject) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != CheckerShortName) + { + return null; + } + + var nameArray = jsonObject["N"] as JsonArray; + if (nameArray == null) + { + throw new AbpException("'N' is not an array in the serialized state checker! JsonObject: " + jsonObject.ToJsonString()); + } + + return new RequireFeaturesSimpleStateChecker( + (bool?)jsonObject["A"] ?? false, + nameArray.Select(x => x.ToString()).ToArray() + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs index 1b437e623a..625d097441 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleStateChecker.cs @@ -7,8 +7,8 @@ namespace Volo.Abp.Features; public class RequireFeaturesSimpleStateChecker : ISimpleStateChecker where TState : IHasSimpleStateCheckers { - private readonly string[] _featureNames; - private readonly bool _requiresAll; + public string[] FeatureNames { get; } + public bool RequiresAll { get; } public RequireFeaturesSimpleStateChecker(params string[] featureNames) : this(true, featureNames) @@ -19,13 +19,13 @@ public class RequireFeaturesSimpleStateChecker : ISimpleStateChecker IsEnabledAsync(SimpleStateCheckerContext context) { var featureChecker = context.ServiceProvider.GetRequiredService(); - return await featureChecker.IsEnabledAsync(_requiresAll, _featureNames); + return await featureChecker.IsEnabledAsync(RequiresAll, FeatureNames); } } diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs index 00f72e423d..d140bbcc78 100644 --- a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs @@ -9,6 +9,8 @@ public class GlobalFeaturesSimpleStateCheckerSerializerContributor : ISimpleStateCheckerSerializerContributor, ISingletonDependency { + public const string CheckerShortName = "G"; + public string SerializeToJson(ISimpleStateChecker checker) where TState : IHasSimpleStateCheckers { @@ -18,7 +20,7 @@ public class GlobalFeaturesSimpleStateCheckerSerializerContributor : } var jsonObject = new JsonObject { - ["T"] = "GF", + ["T"] = CheckerShortName, ["A"] = globalFeaturesSimpleStateChecker.RequiresAll }; @@ -35,7 +37,7 @@ public class GlobalFeaturesSimpleStateCheckerSerializerContributor : public ISimpleStateChecker Deserialize(JsonObject jsonObject) where TState : IHasSimpleStateCheckers { - if (jsonObject["T"]?.ToString() != "GF") + if (jsonObject["T"]?.ToString() != CheckerShortName) { return null; } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs similarity index 100% rename from framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs rename to framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs new file mode 100644 index 0000000000..28f7bb0b5e --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using Shouldly; +using Volo.Abp.SimpleStateChecking; +using Xunit; + +namespace Volo.Abp.Features; + +public class FeaturesSimpleStateCheckerSerializerContributor_Tests +{ + [Fact] + public void Should_Serialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new FeaturesSimpleStateCheckerSerializerContributor(); + + var result = serializer.SerializeToJson( + new RequireFeaturesSimpleStateChecker( + "FeatureA", + "FeatureB" + ) + ); + + result.ShouldBe("{\"T\":\"F\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + } + + [Fact] + public void Should_Deserialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new FeaturesSimpleStateCheckerSerializerContributor(); + + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"F\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + var checker = serializer.Deserialize(jsonObject); + + checker.ShouldBeOfType>(); + var globalFeaturesSimpleStateChecker = checker as RequireFeaturesSimpleStateChecker; + globalFeaturesSimpleStateChecker.ShouldNotBeNull(); + globalFeaturesSimpleStateChecker.RequiresAll.ShouldBeTrue(); + globalFeaturesSimpleStateChecker.FeatureNames[0].ShouldBe("FeatureA"); + globalFeaturesSimpleStateChecker.FeatureNames[1].ShouldBe("FeatureB"); + } + + private class MyState : IHasSimpleStateCheckers + { + public List> StateCheckers { get; } = new(); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs index 46064bd11e..c4878abca3 100644 --- a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs +++ b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -20,7 +20,7 @@ public class GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests ) ); - result.ShouldBe("{\"T\":\"GF\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + result.ShouldBe("{\"T\":\"G\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); } [Fact] @@ -28,7 +28,7 @@ public class GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests { var serializer = new GlobalFeaturesSimpleStateCheckerSerializerContributor(); - var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"GF\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"G\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); var checker = serializer.Deserialize(jsonObject); checker.ShouldBeOfType>(); From 9987b0650e48253d1026ace727c60f0e210757e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 14:52:59 +0300 Subject: [PATCH 49/70] Implemented PermissionsSimpleStateCheckerSerializerContributor and revised serializing. --- ...SimpleStateCheckerSerializerContributor.cs | 4 +- ...SimpleStateCheckerSerializerContributor.cs | 62 +++++++++++++++++++ .../RequirePermissionsSimpleStateChecker.cs | 4 ++ .../ISimpleStateCheckerSerializer.cs | 2 +- ...SimpleStateCheckerSerializerContributor.cs | 2 +- .../SimpleStateCheckerSerializer.cs | 4 +- .../SimpleStateCheckerSerializerExtensions.cs | 7 ++- ...SimpleStateCheckerSerializerContributor.cs | 2 +- ...SimpleStateCheckerSerializerContributor.cs | 2 +- ...StateCheckerSerializerContributor_Tests.cs | 2 +- ...StateCheckerSerializerContributor_Tests.cs | 2 +- ...StateCheckerSerializerContributor_Tests.cs | 2 +- ...cPermissionDefinitionStoreInMemoryCache.cs | 5 +- .../PermissionDefinitionSerializer_Tests.cs | 6 +- 14 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionsSimpleStateCheckerSerializerContributor.cs diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs index cb52f5f7ac..2a23b5bfcd 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs @@ -13,7 +13,7 @@ public class AuthenticatedSimpleStateCheckerSerializerContributor : public string SerializeToJson(ISimpleStateChecker checker) where TState : IHasSimpleStateCheckers { - if (checker is not RequireAuthenticatedSimpleStateChecker requireAuthenticatedSimpleStateChecker) + if (checker is not RequireAuthenticatedSimpleStateChecker) { return null; } @@ -25,7 +25,7 @@ public class AuthenticatedSimpleStateCheckerSerializerContributor : return jsonObject.ToJsonString(); } - public ISimpleStateChecker Deserialize(JsonObject jsonObject) + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) where TState : IHasSimpleStateCheckers { if (jsonObject["T"]?.ToString() != CheckerShortName) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionsSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionsSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..3b890797f6 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionsSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,62 @@ +using System.Linq; +using System.Text.Json.Nodes; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.GlobalFeatures; + +public class PermissionsSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "P"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequirePermissionsSimpleStateChecker permissionsSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName, + ["A"] = permissionsSimpleStateChecker.RequiresAll + }; + + var nameArray = new JsonArray(); + foreach (var permissionName in permissionsSimpleStateChecker.PermissionNames) + { + nameArray.Add(permissionName); + } + + jsonObject["N"] = nameArray; + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize( + JsonObject jsonObject, + TState state) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != CheckerShortName) + { + return null; + } + + var nameArray = jsonObject["N"] as JsonArray; + if (nameArray == null) + { + throw new AbpException("'N' is not an array in the serialized state checker! JsonObject: " + jsonObject.ToJsonString()); + } + + return new RequirePermissionsSimpleStateChecker( + new RequirePermissionsSimpleBatchStateCheckerModel( + state, + nameArray.Select(x => x.ToString()).ToArray(), + (bool?)jsonObject["A"] ?? false + ) + ); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs index 3ae1809b55..fd8eef3791 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleStateChecker.cs @@ -8,6 +8,10 @@ namespace Volo.Abp.Authorization.Permissions; public class RequirePermissionsSimpleStateChecker : ISimpleStateChecker where TState : IHasSimpleStateCheckers { + public bool RequiresAll => _model.RequiresAll; + + public string[] PermissionNames => _model.Permissions; + private readonly RequirePermissionsSimpleBatchStateCheckerModel _model; public RequirePermissionsSimpleStateChecker(RequirePermissionsSimpleBatchStateCheckerModel model) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs index 00191b03d2..ffbed53cf7 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs @@ -7,6 +7,6 @@ public interface ISimpleStateCheckerSerializer public string Serialize(ISimpleStateChecker checker) where TState : IHasSimpleStateCheckers; - public ISimpleStateChecker Deserialize(JsonObject jsonObject) + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) where TState : IHasSimpleStateCheckers; } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs index b36c41347e..d65c90eee6 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializerContributor.cs @@ -10,6 +10,6 @@ public interface ISimpleStateCheckerSerializerContributor where TState : IHasSimpleStateCheckers; [CanBeNull] - public ISimpleStateChecker Deserialize(JsonObject jsonObject) + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) where TState : IHasSimpleStateCheckers; } \ No newline at end of file diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs index 9e7cfd47f7..d5d931ffae 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs @@ -33,12 +33,12 @@ public class SimpleStateCheckerSerializer : } [CanBeNull] - public ISimpleStateChecker Deserialize(JsonObject jsonObject) + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) where TState : IHasSimpleStateCheckers { foreach (var contributor in _contributors) { - var result = contributor.Deserialize(jsonObject); + var result = contributor.Deserialize(jsonObject, state); if (result != null) { return result; diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs index 3c852fc901..1e4d272379 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs @@ -41,7 +41,8 @@ public static class SimpleStateCheckerSerializerExtensions public static ISimpleStateChecker[] DeserializeArray( this ISimpleStateCheckerSerializer serializer, - string value) + string value, + TState state) where TState : IHasSimpleStateCheckers { if (value.IsNullOrWhiteSpace()) @@ -63,7 +64,7 @@ public static class SimpleStateCheckerSerializerExtensions throw new AbpException("JSON value is not an array of objects: " + value); } - var checker = serializer.Deserialize(jsonObject); + var checker = serializer.Deserialize(jsonObject, state); if (checker == null) { return Array.Empty>(); @@ -81,7 +82,7 @@ public static class SimpleStateCheckerSerializerExtensions throw new AbpException("JSON value is not an array of objects: " + value); } - checkers[i] = serializer.Deserialize(jsonObject); + checkers[i] = serializer.Deserialize(jsonObject, state); } return checkers.Where(x => x != null).ToArray(); diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs index 7510cb4a24..58e2817139 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs @@ -34,7 +34,7 @@ public class FeaturesSimpleStateCheckerSerializerContributor : return jsonObject.ToJsonString(); } - public ISimpleStateChecker Deserialize(JsonObject jsonObject) + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) where TState : IHasSimpleStateCheckers { if (jsonObject["T"]?.ToString() != CheckerShortName) diff --git a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs index d140bbcc78..d4abc25403 100644 --- a/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs @@ -34,7 +34,7 @@ public class GlobalFeaturesSimpleStateCheckerSerializerContributor : return jsonObject.ToJsonString(); } - public ISimpleStateChecker Deserialize(JsonObject jsonObject) + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) where TState : IHasSimpleStateCheckers { if (jsonObject["T"]?.ToString() != CheckerShortName) diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs index b6ae8bace4..0d84d167de 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_Tests.cs @@ -27,7 +27,7 @@ public class AuthenticatedSimpleStateCheckerSerializerContributor_Tests var serializer = new AuthenticatedSimpleStateCheckerSerializerContributor(); var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"A\"}"); - var checker = serializer.Deserialize(jsonObject); + var checker = serializer.Deserialize(jsonObject, new MyState()); checker.ShouldBeOfType>(); var globalFeaturesSimpleStateChecker = checker as RequireAuthenticatedSimpleStateChecker; diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs index 28f7bb0b5e..9791ac44bc 100644 --- a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -29,7 +29,7 @@ public class FeaturesSimpleStateCheckerSerializerContributor_Tests var serializer = new FeaturesSimpleStateCheckerSerializerContributor(); var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"F\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); - var checker = serializer.Deserialize(jsonObject); + var checker = serializer.Deserialize(jsonObject, new MyState()); checker.ShouldBeOfType>(); var globalFeaturesSimpleStateChecker = checker as RequireFeaturesSimpleStateChecker; diff --git a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs index c4878abca3..e0425775dc 100644 --- a/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs +++ b/framework/test/Volo.Abp.GlobalFeatures.Tests/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests.cs @@ -29,7 +29,7 @@ public class GlobalFeaturesSimpleStateCheckerSerializerContributor_Tests var serializer = new GlobalFeaturesSimpleStateCheckerSerializerContributor(); var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"G\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); - var checker = serializer.Deserialize(jsonObject); + var checker = serializer.Deserialize(jsonObject, new MyState()); checker.ShouldBeOfType>(); var globalFeaturesSimpleStateChecker = checker as RequireGlobalFeaturesSimpleStateChecker; diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs index 4e567aadea..30818ada68 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -100,8 +100,9 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : if (!permissionRecord.StateCheckers.IsNullOrWhiteSpace()) { var checkers = StateCheckerSerializer - .DeserializeArray( - permissionRecord.StateCheckers + .DeserializeArray( + permissionRecord.StateCheckers, + permission ); permission.StateCheckers.AddRange(checkers); } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index 21f18cca1d..efef577a98 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -54,7 +54,9 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase ) .WithProviders("ProviderA", "ProviderB") .WithProperty("CustomProperty2", "CustomValue2") - .RequireGlobalFeatures("GlobalFeature1", "GlobalFeature2"); + .RequireAuthenticated() //For for testing, not so meaningful + .RequireGlobalFeatures("GlobalFeature1", "GlobalFeature2") + .RequireFeatures("Feature1", "Feature2"); // Act @@ -71,7 +73,7 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); permissionRecord.Providers.ShouldBe("ProviderA,ProviderB"); permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); - permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"GF\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]}]"); + permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"A\"},{\"T\":\"G\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]},{\"T\":\"F\",\"A\":true,\"N\":[\"Feature1\",\"Feature2\"]}]"); } private static PermissionGroupDefinition CreatePermissionGroup1( From d9cf4d79c40a234132157c410cf612d945b8b714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 14:55:33 +0300 Subject: [PATCH 50/70] Update PermissionDefinitionSerializer_Tests.cs --- .../PermissionDefinitionSerializer_Tests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index efef577a98..eed7a3435a 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -56,7 +56,8 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase .WithProperty("CustomProperty2", "CustomValue2") .RequireAuthenticated() //For for testing, not so meaningful .RequireGlobalFeatures("GlobalFeature1", "GlobalFeature2") - .RequireFeatures("Feature1", "Feature2"); + .RequireFeatures("Feature1", "Feature2") + .RequirePermissions(requiresAll: false, batchCheck: false,"Permission2", "Permission3"); // Act @@ -73,7 +74,7 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); permissionRecord.Providers.ShouldBe("ProviderA,ProviderB"); permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); - permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"A\"},{\"T\":\"G\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]},{\"T\":\"F\",\"A\":true,\"N\":[\"Feature1\",\"Feature2\"]}]"); + permissionRecord.StateCheckers.ShouldBe("[{\"T\":\"A\"},{\"T\":\"G\",\"A\":true,\"N\":[\"GlobalFeature1\",\"GlobalFeature2\"]},{\"T\":\"F\",\"A\":true,\"N\":[\"Feature1\",\"Feature2\"]},{\"T\":\"P\",\"A\":false,\"N\":[\"Permission2\",\"Permission3\"]}]"); } private static PermissionGroupDefinition CreatePermissionGroup1( From 84ae7e8e12851b5fef133f72875b18d61a5b98ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 15:32:28 +0300 Subject: [PATCH 51/70] Delay for checking latest permissions --- .../DynamicPermissionDefinitionStore.cs | 13 +++++++++---- ...DynamicPermissionDefinitionStoreInMemoryCache.cs | 2 ++ ...DynamicPermissionDefinitionStoreInMemoryCache.cs | 3 +++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index 0e8b28d38e..2a507c2ab5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -78,22 +78,27 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor private async Task EnsureCacheIsUptoDateAsync() { - /* TODO: Optimization note: May not check for a few seconds - * It is acceptable to get changes a few seconds after the last time the cache was updated. - */ - using (await StoreCache.SyncSemaphore.LockAsync()) { + if (StoreCache.LastCheckTime.HasValue && + DateTime.Now.Subtract(StoreCache.LastCheckTime.Value).TotalSeconds < 30) + { + /* We get the latest permission with a small delay for optimization */ + return; + } + var stampInDistributedCache = await GetOrSetStampInDistributedCache(); if (stampInDistributedCache == StoreCache.CacheStamp) { + StoreCache.LastCheckTime = DateTime.Now; return; } await UpdateInMemoryStoreCache(); StoreCache.CacheStamp = stampInDistributedCache; + StoreCache.LastCheckTime = DateTime.Now; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs index 30818ada68..185d1c6fee 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -21,6 +21,8 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } public SemaphoreSlim SyncSemaphore { get; } = new(1, 1); + + public DateTime? LastCheckTime { get; set; } public DynamicPermissionDefinitionStoreInMemoryCache(ISimpleStateCheckerSerializer stateCheckerSerializer) { diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs index e6a1da3b79..2dab588ebd 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -11,6 +12,8 @@ public interface IDynamicPermissionDefinitionStoreInMemoryCache SemaphoreSlim SyncSemaphore { get; } + DateTime? LastCheckTime { get; set; } + Task FillAsync( List permissionGroupRecords, List permissionRecords); From c6da9ba0a9ef67ba2cbb9ef341a7e3a6dbb33b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 15:56:33 +0300 Subject: [PATCH 52/70] Use cancellationtoken in distributed locking. --- .../Volo.Abp.DistributedLocking.csproj | 1 + .../AbpDistributedLockingModule.cs | 4 +++- .../MedallionAbpDistributedLock.cs | 16 ++++++++++++++-- .../Threading/NullCancellationTokenProvider.cs | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj b/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj index fd9b992133..0abb5e699c 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj +++ b/framework/src/Volo.Abp.DistributedLocking/Volo.Abp.DistributedLocking.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs index 4c4abd3f32..853752cb6c 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs +++ b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/AbpDistributedLockingModule.cs @@ -1,9 +1,11 @@ using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.DistributedLocking; [DependsOn( - typeof(AbpDistributedLockingAbstractionsModule) + typeof(AbpDistributedLockingAbstractionsModule), + typeof(AbpThreadingModule) )] public class AbpDistributedLockingModule : AbpModule { diff --git a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs index e78f1934c1..769303a348 100644 --- a/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs +++ b/framework/src/Volo.Abp.DistributedLocking/Volo/Abp/DistributedLocking/MedallionAbpDistributedLock.cs @@ -3,6 +3,7 @@ using System.Threading; using System.Threading.Tasks; using Medallion.Threading; using Volo.Abp.DependencyInjection; +using Volo.Abp.Threading; namespace Volo.Abp.DistributedLocking; @@ -10,10 +11,14 @@ namespace Volo.Abp.DistributedLocking; public class MedallionAbpDistributedLock : IAbpDistributedLock, ITransientDependency { protected IDistributedLockProvider DistributedLockProvider { get; } + protected ICancellationTokenProvider CancellationTokenProvider { get; } - public MedallionAbpDistributedLock(IDistributedLockProvider distributedLockProvider) + public MedallionAbpDistributedLock( + IDistributedLockProvider distributedLockProvider, + ICancellationTokenProvider cancellationTokenProvider) { DistributedLockProvider = distributedLockProvider; + CancellationTokenProvider = cancellationTokenProvider; } public async Task TryAcquireAsync( @@ -23,7 +28,14 @@ public class MedallionAbpDistributedLock : IAbpDistributedLock, ITransientDepend { Check.NotNullOrWhiteSpace(name, nameof(name)); - var handle = await DistributedLockProvider.TryAcquireLockAsync(name, timeout, cancellationToken); + CancellationTokenProvider.FallbackToProvider(cancellationToken); + + var handle = await DistributedLockProvider.TryAcquireLockAsync( + name, + timeout, + CancellationTokenProvider.FallbackToProvider(cancellationToken) + ); + if (handle == null) { return null; diff --git a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs index 8f8113ba0d..2da06632cd 100644 --- a/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs +++ b/framework/src/Volo.Abp.Threading/Volo/Abp/Threading/NullCancellationTokenProvider.cs @@ -4,7 +4,7 @@ namespace Volo.Abp.Threading; public class NullCancellationTokenProvider : CancellationTokenProviderBase { - public static NullCancellationTokenProvider Instance { get; } = new NullCancellationTokenProvider(); + public static NullCancellationTokenProvider Instance { get; } = new(); public override CancellationToken Token => OverrideValue?.CancellationToken ?? CancellationToken.None; From 9c8b5ee79c833965c337569dae4ed6ec36685546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 15:57:24 +0300 Subject: [PATCH 53/70] Use hostApplicationLifetime.ApplicationStopping to cancel the operation for saving permissions --- .../AbpPermissionManagementDomainModule.cs | 49 +++++++++++-------- .../StaticPermissionSaver.cs | 24 ++++++--- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index ac0ddd8b1c..097c74667e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Polly; @@ -10,6 +11,7 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Domain; using Volo.Abp.Json; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.PermissionManagement; @@ -37,36 +39,41 @@ public class AbpPermissionManagementDomainModule : AbpModule private static void SaveStaticPermissionsToDatabase(ApplicationInitializationContext context) { var rootServiceProvider = context.ServiceProvider.GetRequiredService(); + var hostApplicationLifetime = context.ServiceProvider.GetRequiredService(); Task.Run(async () => { using var scope = rootServiceProvider.CreateScope(); + var cancellationTokenProvider = scope.ServiceProvider.GetRequiredService(); try { - await Policy - .Handle() - .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) - .ExecuteAsync(async () => - { - try + using (cancellationTokenProvider.Use(hostApplicationLifetime.ApplicationStopping)) + { + await Policy + .Handle() + .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) + .ExecuteAsync(async _ => { - // ReSharper disable once AccessToDisposedClosure - await scope - .ServiceProvider - .GetRequiredService() - .SaveAsync(); - } - catch (Exception ex) - { - // ReSharper disable once AccessToDisposedClosure - scope.ServiceProvider - .GetService>()? - .LogException(ex); + try + { + // ReSharper disable once AccessToDisposedClosure + await scope + .ServiceProvider + .GetRequiredService() + .SaveAsync(); + } + catch (Exception ex) + { + // ReSharper disable once AccessToDisposedClosure + scope.ServiceProvider + .GetService>()? + .LogException(ex); - throw; // Polly will catch it - } - }); + throw; // Polly will catch it + } + }, cancellationTokenProvider.Token); + } } // ReSharper disable once EmptyGeneralCatchClause (No need to log since it is logged above) catch { } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index f3f8674755..30f88e8c2d 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -10,6 +10,7 @@ using Volo.Abp.Authorization.Permissions; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.DistributedLocking; +using Volo.Abp.Threading; using Volo.Abp.Uow; namespace Volo.Abp.PermissionManagement; @@ -24,6 +25,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc protected IApplicationNameAccessor ApplicationNameAccessor { get; } protected IAbpDistributedLock DistributedLock { get; } protected PermissionManagementOptions PermissionManagementOptions { get; } + protected ICancellationTokenProvider CancellationTokenProvider { get; } protected AbpDistributedCacheOptions CacheOptions { get; } public StaticPermissionSaver( @@ -35,7 +37,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc IOptions cacheOptions, IApplicationNameAccessor applicationNameAccessor, IAbpDistributedLock distributedLock, - IOptions permissionManagementOptions) + IOptions permissionManagementOptions, + ICancellationTokenProvider cancellationTokenProvider) { StaticStore = staticStore; PermissionGroupRepository = permissionGroupRepository; @@ -44,6 +47,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc Cache = cache; ApplicationNameAccessor = applicationNameAccessor; DistributedLock = distributedLock; + CancellationTokenProvider = cancellationTokenProvider; PermissionManagementOptions = permissionManagementOptions.Value; CacheOptions = cacheOptions.Value; } @@ -53,7 +57,10 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc { /* TODO: We may double check and lock for optimization */ - await using var applicationLockHandle = await DistributedLock.TryAcquireAsync(GetApplicationDistributedLockKey()); + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( + GetApplicationDistributedLockKey() + ); + if (applicationLockHandle == null) { /* Another application instance is already doing it */ @@ -66,7 +73,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc */ var cacheKey = GetApplicationHashCacheKey(); - var cachedHash = await Cache.GetStringAsync(cacheKey); + var cachedHash = await Cache.GetStringAsync(cacheKey, CancellationTokenProvider.Token); var (permissionGroupRecords, permissionRecords) = await PermissionSerializer.SerializeAsync( await StaticStore.GetGroupsAsync() @@ -84,8 +91,9 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc return; } - await using (var commonLockHandle = await DistributedLock - .TryAcquireAsync(GetCommonDistributedLockKey(), TimeSpan.FromMinutes(5))) + await using (var commonLockHandle = await DistributedLock.TryAcquireAsync( + GetCommonDistributedLockKey(), + TimeSpan.FromMinutes(5))) { if (commonLockHandle == null) { @@ -103,7 +111,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc Guid.NewGuid().ToString(), new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? - } + }, + CancellationTokenProvider.Token ); } } @@ -113,7 +122,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc currentHash, new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? - } + }, + CancellationTokenProvider.Token ); } From 3503f6f7d64e84cf26a02d06a459256377d2d869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 15:58:41 +0300 Subject: [PATCH 54/70] Try more to save permissions --- .../PermissionManagement/AbpPermissionManagementDomainModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index 097c74667e..72d2bb9eef 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -52,7 +52,7 @@ public class AbpPermissionManagementDomainModule : AbpModule { await Policy .Handle() - .WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) + .WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) .ExecuteAsync(async _ => { try From e7b4a8da4d70f10f1675d355ac0f0f8fc385a5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 16:17:07 +0300 Subject: [PATCH 55/70] use PollyPackageVersion variable. --- .../Volo.Abp.PermissionManagement.Domain.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj index 39ec0e9763..f9eb16d965 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj @@ -24,7 +24,7 @@ - + From 1f346914f54c02c4093fcfb7485c18e0a5cd2353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 16:44:39 +0300 Subject: [PATCH 56/70] LocalizableString fallbacks to the default resource. --- .../Abp/Localization/LocalizableString.cs | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs index 61494d609e..765f3f7717 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs @@ -20,7 +20,28 @@ public class LocalizableString : ILocalizableString public LocalizedString Localize(IStringLocalizerFactory stringLocalizerFactory) { - return stringLocalizerFactory.Create(ResourceType)[Name]; + var localizer = ResourceType != null + ? stringLocalizerFactory.Create(ResourceType) + : stringLocalizerFactory.CreateDefaultOrNull(); + + if (localizer == null) + { + throw new AbpException($"Set {nameof(ResourceType)} or configure the default localization resource type (in the AbpLocalizationOptions)!"); + } + + var result = localizer[Name]; + + if (result.ResourceNotFound && ResourceType != null) + { + /* Search in the default resource if not found in the provided resource */ + localizer = stringLocalizerFactory.CreateDefaultOrNull(); + if (localizer != null) + { + result = localizer[Name]; + } + } + + return result; } public static LocalizableString Create([NotNull] string name) From fea95f4de2d8d417384f25feb76cc92d706ee19c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 16:44:52 +0300 Subject: [PATCH 57/70] Remove unused methods from PermissionDefinitionSerializer --- .../PermissionDefinitionSerializer.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index c7a8dac1bb..c99ee51f24 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Localization; using Volo.Abp.Authorization.Permissions; @@ -56,12 +55,6 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I } } - public Task DeserializeAsync( - PermissionDefinitionRecord permissionRecord) - { - throw new System.NotImplementedException(); - } - public Task SerializeAsync(PermissionGroupDefinition permissionGroup) { using (CultureHelper.Use(CultureInfo.InvariantCulture)) @@ -100,11 +93,6 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I return (permissionGroupRecords.ToArray(), permissionRecords.ToArray()); } - public Task DeserializeAsync(PermissionGroupDefinitionRecord permissionGroupRecord) - { - throw new System.NotImplementedException(); - } - protected virtual string SerializeStateCheckers(List> stateCheckers) { return StateCheckerSerializer.Serialize(stateCheckers); From 31b3cdc15d0c70e5a275a0b81840fcdef6b5c24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 18:11:45 +0300 Subject: [PATCH 58/70] Include localization key and resources while getting permission grants from server. --- .../AbpApplicationConfigurationAppService.cs | 4 +- .../LocalizationResourceDictionary.cs | 27 ++++++++- .../PermissionGrantInfoDto.cs | 4 ++ .../PermissionGroupDto.cs | 4 ++ .../PermissionAppService.cs | 52 +++++++++++++----- .../PermissionManagementModal.cshtml.cs | 55 ++++++++++++++++++- 6 files changed, 126 insertions(+), 20 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index fcef74990a..ed314798e6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -214,9 +214,9 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp { var dictionary = new Dictionary(); - var localizer = _serviceProvider.GetRequiredService( + var localizer = (IStringLocalizer) _serviceProvider.GetRequiredService( typeof(IStringLocalizer<>).MakeGenericType(resource.ResourceType) - ) as IStringLocalizer; + ); foreach (var localizedString in localizer.GetAllStrings()) { diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs index e394e01202..d672a2f17a 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs @@ -6,6 +6,8 @@ namespace Volo.Abp.Localization; public class LocalizationResourceDictionary : Dictionary { + private readonly Dictionary _resourcesByNames = new(); + public LocalizationResource Add([CanBeNull] string defaultCultureName = null) { return Add(typeof(TResouce), defaultCultureName); @@ -18,7 +20,12 @@ public class LocalizationResourceDictionary : Dictionary() @@ -33,4 +40,20 @@ public class LocalizationResourceDictionary : Dictionary Permissions { get; set; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs index bc16824913..fd0ccf0246 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Volo.Abp.Application.Services; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; using Volo.Abp.SimpleStateChecking; @@ -45,12 +46,7 @@ public class PermissionAppService : ApplicationService, IPermissionAppService foreach (var group in await PermissionDefinitionManager.GetGroupsAsync()) { - var groupDto = new PermissionGroupDto - { - Name = group.Name, - DisplayName = group.DisplayName.Localize(StringLocalizerFactory), - Permissions = new List() - }; + var groupDto = CreatePermissionGroupDto(group); var neededCheckPermissions = new List(); @@ -70,14 +66,9 @@ public class PermissionAppService : ApplicationService, IPermissionAppService continue; } - var grantInfoDtos = neededCheckPermissions.Select(x => new PermissionGrantInfoDto - { - Name = x.Name, - DisplayName = x.DisplayName.Localize(StringLocalizerFactory), - ParentName = x.Parent?.Name, - AllowedProviders = x.Providers, - GrantedProviders = new List() - }).ToList(); + var grantInfoDtos = neededCheckPermissions + .Select(CreatePermissionGrantInfoDto) + .ToList(); var multipleGrantInfo = await PermissionManager.GetAsync(neededCheckPermissions.Select(x => x.Name).ToArray(), providerName, providerKey); @@ -108,6 +99,39 @@ public class PermissionAppService : ApplicationService, IPermissionAppService return result; } + private PermissionGrantInfoDto CreatePermissionGrantInfoDto(PermissionDefinition permission) + { + var localizableDisplayName = permission.DisplayName as LocalizableString; + + return new PermissionGrantInfoDto { + Name = permission.Name, + DisplayName = permission.DisplayName.Localize(StringLocalizerFactory), + DisplayNameKey = localizableDisplayName?.Name, + DisplayNameResource = localizableDisplayName?.ResourceType != null + ? LocalizationResourceNameAttribute.GetName(localizableDisplayName.ResourceType) + : null, + ParentName = permission.Parent?.Name, + AllowedProviders = permission.Providers, + GrantedProviders = new List() + }; + } + + private PermissionGroupDto CreatePermissionGroupDto(PermissionGroupDefinition group) + { + var localizableDisplayName = group.DisplayName as LocalizableString; + + return new PermissionGroupDto + { + Name = group.Name, + DisplayName = group.DisplayName.Localize(StringLocalizerFactory), + DisplayNameKey = localizableDisplayName?.Name, + DisplayNameResource = localizableDisplayName?.ResourceType != null + ? LocalizationResourceNameAttribute.GetName(localizableDisplayName.ResourceType) + : null, + Permissions = new List() + }; + } + public virtual async Task UpdateAsync(string providerName, string providerKey, UpdatePermissionsDto input) { await CheckProviderPolicy(providerName); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs index 5f1ca18fc0..30057eea82 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs @@ -1,11 +1,14 @@ +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; using Volo.Abp.EventBus.Local; +using Volo.Abp.Localization; using Volo.Abp.PermissionManagement.Web.Utils; namespace Volo.Abp.PermissionManagement.Web.Pages.AbpPermissionManagement; @@ -37,15 +40,18 @@ public class PermissionManagementModal : AbpPageModel protected IPermissionAppService PermissionAppService { get; } protected ILocalEventBus LocalEventBus { get; } + public AbpLocalizationOptions LocalizationOptions { get; } public PermissionManagementModal( - IPermissionAppService permissionAppService, - ILocalEventBus localEventBus) + IPermissionAppService permissionAppService, + ILocalEventBus localEventBus, + IOptions localizationOptions) { ObjectMapperContext = typeof(AbpPermissionManagementWebModule); PermissionAppService = permissionAppService; LocalEventBus = localEventBus; + LocalizationOptions = localizationOptions.Value; } public virtual async Task OnGetAsync() @@ -54,6 +60,8 @@ public class PermissionManagementModal : AbpPageModel var result = await PermissionAppService.GetAsync(ProviderName, ProviderKey); + UpdateLocalizations(result); + EntityDisplayName = !string.IsNullOrWhiteSpace(ProviderKeyDisplayName) ? ProviderKeyDisplayName : result.EntityDisplayName; @@ -78,6 +86,49 @@ public class PermissionManagementModal : AbpPageModel return Page(); } + private void UpdateLocalizations(GetPermissionListResultDto result) + { + foreach (var group in result.Groups) + { + group.DisplayName = Localize( + group.DisplayNameKey, + group.DisplayNameResource, + group.DisplayName + ); + + foreach (var permission in group.Permissions) + { + permission.DisplayName = Localize( + permission.DisplayNameKey, + permission.DisplayNameResource, + permission.DisplayName + ); + } + } + } + + private string Localize(string key, string resourceName, string fallbackValue) + { + if (key.IsNullOrEmpty() || resourceName.IsNullOrEmpty()) + { + return fallbackValue; + } + + var resource = LocalizationOptions.Resources.GetOrNull(resourceName); + if (resource == null) + { + return fallbackValue; + } + + var result = new LocalizableString(resource.ResourceType, key).Localize(StringLocalizerFactory); + if (result.ResourceNotFound) + { + return fallbackValue; + } + + return result.Value; + } + public virtual async Task OnPostAsync() { ValidateModel(); From b1c3a664bb61c0e34d2bfcf41ef792391ca55ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 18:40:15 +0300 Subject: [PATCH 59/70] Introduce ILocalizableStringSerializer --- .../Abp/Localization/LocalizableString.cs | 2 +- .../ILocalizableStringSerializer.cs | 8 +++ .../LocalizableStringSerializer.cs | 64 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizableStringSerializer.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs index 765f3f7717..88eb8a399d 100644 --- a/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs +++ b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs @@ -12,7 +12,7 @@ public class LocalizableString : ILocalizableString [NotNull] public string Name { get; } - public LocalizableString(Type resourceType, [NotNull] string name) + public LocalizableString([CanBeNull] Type resourceType, [NotNull] string name) { Name = Check.NotNullOrEmpty(name, nameof(name)); ResourceType = resourceType; diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizableStringSerializer.cs new file mode 100644 index 0000000000..6f7a487b6c --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizableStringSerializer.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.Localization; + +public interface ILocalizableStringSerializer +{ + string Serialize(ILocalizableString localizableString); + + ILocalizableString Deserialize(string value); +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs new file mode 100644 index 0000000000..b9cd6528fe --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs @@ -0,0 +1,64 @@ +using System; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Localization; + +public class LocalizableStringSerializer : ILocalizableStringSerializer, ITransientDependency +{ + protected AbpLocalizationOptions LocalizationOptions { get; } + + public LocalizableStringSerializer(IOptions localizationOptions) + { + LocalizationOptions = localizationOptions.Value; + } + + public virtual string Serialize(ILocalizableString localizableString) + { + if (localizableString is LocalizableString realLocalizableString) + { + return $"L:{LocalizationResourceNameAttribute.GetName(realLocalizableString.ResourceType)},{realLocalizableString.Name}"; + } + + if (localizableString is FixedLocalizableString fixedLocalizableString) + { + return $"F:{fixedLocalizableString.Value}"; + } + + throw new AbpException($"Unknown {nameof(ILocalizableString)} type: {localizableString.GetType().FullName}"); + } + + public virtual ILocalizableString Deserialize(string value) + { + if (value.IsNullOrEmpty() || + value.Length < 3 || + value[1] != ':') + { + return new FixedLocalizableString(value); + } + + var type = value[0]; + switch (type) + { + case 'F': + return new FixedLocalizableString(value.Substring(2)); + case 'L': + var commaPosition = value.IndexOf(',', 2); + if (commaPosition == -1) + { + throw new AbpException("Invalid LocalizableString value: " + value); + } + + var resourceName = value.Substring(2, commaPosition - 2); + var name = value.Substring(commaPosition + 1); + var resourceType = LocalizationOptions.Resources.GetOrNull(resourceName)?.ResourceType; + + return new LocalizableString( + resourceType, + name + ); + default: + return new FixedLocalizableString(value); + } + } +} \ No newline at end of file From 08cced9f9f34ea3f198d85c04a19ae79bd87a8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 18:44:10 +0300 Subject: [PATCH 60/70] Add missing `await`. --- .../AbpApplicationConfigurationAppService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index ed314798e6..7bcc0b3cd9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -171,7 +171,8 @@ public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApp foreach (var policyName in policyNames) { - if (await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && _permissionDefinitionManager.GetOrNullAsync(policyName) != null) + if (await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && + await _permissionDefinitionManager.GetOrNullAsync(policyName) != null) { abpPolicyNames.Add(policyName); } From 6f5380ab39c98c5e49067d7b261819309b60db06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 19 Aug 2022 21:29:58 +0300 Subject: [PATCH 61/70] Added tests for LocalizableStringSerializer --- .../LocalizableStringSerializer.cs | 5 ++ .../Localization/AbpLocalizationTestModule.cs | 39 ++++++++++ .../Abp/Localization/AbpLocalization_Tests.cs | 45 +---------- .../LocalizableStringSerializer_Tests.cs | 75 +++++++++++++++++++ .../Source/LocalizationTestResource.cs | 1 + 5 files changed, 122 insertions(+), 43 deletions(-) create mode 100644 framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs create mode 100644 framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/LocalizableStringSerializer_Tests.cs diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs index b9cd6528fe..4cfd6e2f32 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs @@ -51,6 +51,11 @@ public class LocalizableStringSerializer : ILocalizableStringSerializer, ITransi var resourceName = value.Substring(2, commaPosition - 2); var name = value.Substring(commaPosition + 1); + if (name.IsNullOrWhiteSpace()) + { + throw new AbpException("Invalid LocalizableString value: " + value); + } + var resourceType = LocalizationOptions.Resources.GetOrNull(resourceName)?.ResourceType; return new LocalizableString( diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs new file mode 100644 index 0000000000..340d091330 --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalizationTestModule.cs @@ -0,0 +1,39 @@ +using Volo.Abp.Localization.TestResources.Base.CountryNames; +using Volo.Abp.Localization.TestResources.Base.Validation; +using Volo.Abp.Localization.TestResources.Source; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.Localization; + +[DependsOn(typeof(AbpTestBaseModule))] +[DependsOn(typeof(AbpLocalizationModule))] +public class AbpLocalizationTestModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/Validation"); + + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/CountryNames"); + + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Localization/TestResources/Source"); + + options.Resources + .Get() + .AddVirtualJson("/Volo/Abp/Localization/TestResources/SourceExt"); + }); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index 6c4bdfff08..d643f163b9 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -2,17 +2,13 @@ using System.Globalization; using System.Linq; using Microsoft.Extensions.Localization; using Shouldly; -using Volo.Abp.Localization.TestResources.Base.CountryNames; -using Volo.Abp.Localization.TestResources.Base.Validation; using Volo.Abp.Localization.TestResources.Source; -using Volo.Abp.Modularity; using Volo.Abp.Testing; -using Volo.Abp.VirtualFileSystem; using Xunit; namespace Volo.Abp.Localization; -public class AbpLocalization_Tests : AbpIntegratedTest +public class AbpLocalization_Tests : AbpIntegratedTest { private readonly IStringLocalizer _localizer; private readonly IStringLocalizerFactory _localizerFactory; @@ -76,7 +72,6 @@ public class AbpLocalization_Tests : AbpIntegratedTest ls.Name == "USA"); } - } [Fact] @@ -275,7 +268,6 @@ public class AbpLocalization_Tests : AbpIntegratedTest(options => - { - options.FileSets.AddEmbedded(); - }); - - Configure(options => - { - options.Resources - .Add("en") - .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/Validation"); - - options.Resources - .Add("en") - .AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/CountryNames"); - - options.Resources - .Add("en") - .AddVirtualJson("/Volo/Abp/Localization/TestResources/Source"); - - options.Resources - .Get() - .AddVirtualJson("/Volo/Abp/Localization/TestResources/SourceExt"); - }); - } - } -} +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/LocalizableStringSerializer_Tests.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/LocalizableStringSerializer_Tests.cs new file mode 100644 index 0000000000..d8fc1717d2 --- /dev/null +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/LocalizableStringSerializer_Tests.cs @@ -0,0 +1,75 @@ +using Shouldly; +using Volo.Abp.Localization.TestResources.Source; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Localization; + +public class LocalizableStringSerializer_Tests : AbpIntegratedTest +{ + private readonly ILocalizableStringSerializer _serializer; + + public LocalizableStringSerializer_Tests() + { + _serializer = GetRequiredService(); + } + + [Fact] + public void Serialize_FixedLocalizableString() + { + _serializer + .Serialize(new FixedLocalizableString("")) + .ShouldBe("F:"); + + _serializer + .Serialize(new FixedLocalizableString("Hello World")) + .ShouldBe("F:Hello World"); + } + + [Fact] + public void Serialize_LocalizableString() + { + _serializer + .Serialize(new LocalizableString(typeof(LocalizationTestResource),"Car")) + .ShouldBe("L:Test,Car"); + } + + [Fact] + public void Deserialize_FixedLocalizableString() + { + _serializer + .Deserialize("") + .ShouldBeOfType() + .Value.ShouldBe(""); + + _serializer + .Deserialize("Hello") + .ShouldBeOfType() + .Value.ShouldBe("Hello"); + + _serializer + .Deserialize("F:Hello") + .ShouldBeOfType() + .Value.ShouldBe("Hello"); + } + + [Fact] + public void Deserialize_LocalizableString() + { + var localizableString = _serializer + .Deserialize("L:Test,Car") + .ShouldBeOfType(); + localizableString.ResourceType.ShouldBe(typeof(LocalizationTestResource)); + localizableString.Name.ShouldBe("Car"); + + Assert.Throws(() => + { + _serializer.Deserialize("L:Test"); + }); + + Assert.Throws(() => + { + _serializer.Deserialize("L:Test, "); + }); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs index 772acd78d3..bc32e98bcc 100644 --- a/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs +++ b/framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TestResources/Source/LocalizationTestResource.cs @@ -7,6 +7,7 @@ namespace Volo.Abp.Localization.TestResources.Source; typeof(LocalizationTestValidationResource), typeof(LocalizationTestCountryNamesResource) )] +[LocalizationResourceName("Test")] public sealed class LocalizationTestResource { From e1a09e48a101988d429d375393bb541060c1ae84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 21 Aug 2022 11:32:46 +0300 Subject: [PATCH 62/70] Refactor: Re-order methods. --- .../IPermissionDefinitionSerializer.cs | 10 +-- .../PermissionDefinitionSerializer.cs | 82 +++++++++---------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs index ce76afc10c..8ed09a4380 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs @@ -7,13 +7,13 @@ namespace Volo.Abp.PermissionManagement; public interface IPermissionDefinitionSerializer { - Task SerializeAsync( - PermissionDefinition permission, - [CanBeNull] PermissionGroupDefinition permissionGroup); + Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> + SerializeAsync(IEnumerable permissionGroups); Task SerializeAsync( PermissionGroupDefinition permissionGroup); - Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> - SerializeAsync(IEnumerable permissionGroups); + Task SerializeAsync( + PermissionDefinition permission, + [CanBeNull] PermissionGroupDefinition permissionGroup); } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index c99ee51f24..49104c85b6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -27,34 +27,26 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I GuidGenerator = guidGenerator; StringLocalizerFactory = stringLocalizerFactory; } - - public Task SerializeAsync( - PermissionDefinition permission, - PermissionGroupDefinition permissionGroup) + + public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> + SerializeAsync(IEnumerable permissionGroups) { - using (CultureHelper.Use(CultureInfo.InvariantCulture)) + var permissionGroupRecords = new List(); + var permissionRecords = new List(); + + foreach (var permissionGroup in permissionGroups) { - var permissionRecord = new PermissionDefinitionRecord( - GuidGenerator.Create(), - permissionGroup?.Name, - permission.Name, - permission.Parent?.Name, - permission.DisplayName.Localize(StringLocalizerFactory), - permission.IsEnabled, - permission.MultiTenancySide, - SerializeProviders(permission.Providers), - SerializeStateCheckers(permission.StateCheckers) - ); - - foreach (var property in permission.Properties) + permissionGroupRecords.Add(await SerializeAsync(permissionGroup)); + + foreach (var permission in permissionGroup.GetPermissionsWithChildren()) { - permissionRecord.SetProperty(property.Key, property.Value); + permissionRecords.Add(await SerializeAsync(permission, permissionGroup)); } - - return Task.FromResult(permissionRecord); } - } + return (permissionGroupRecords.ToArray(), permissionRecords.ToArray()); + } + public Task SerializeAsync(PermissionGroupDefinition permissionGroup) { using (CultureHelper.Use(CultureInfo.InvariantCulture)) @@ -73,35 +65,43 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I return Task.FromResult(permissionGroupRecord); } } - - public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> - SerializeAsync(IEnumerable permissionGroups) + + public Task SerializeAsync( + PermissionDefinition permission, + PermissionGroupDefinition permissionGroup) { - var permissionGroupRecords = new List(); - var permissionRecords = new List(); - - foreach (var permissionGroup in permissionGroups) + using (CultureHelper.Use(CultureInfo.InvariantCulture)) { - permissionGroupRecords.Add(await SerializeAsync(permissionGroup)); - - foreach (var permission in permissionGroup.GetPermissionsWithChildren()) + var permissionRecord = new PermissionDefinitionRecord( + GuidGenerator.Create(), + permissionGroup?.Name, + permission.Name, + permission.Parent?.Name, + permission.DisplayName.Localize(StringLocalizerFactory), + permission.IsEnabled, + permission.MultiTenancySide, + SerializeProviders(permission.Providers), + SerializeStateCheckers(permission.StateCheckers) + ); + + foreach (var property in permission.Properties) { - permissionRecords.Add(await SerializeAsync(permission, permissionGroup)); + permissionRecord.SetProperty(property.Key, property.Value); } + + return Task.FromResult(permissionRecord); } - - return (permissionGroupRecords.ToArray(), permissionRecords.ToArray()); - } - - protected virtual string SerializeStateCheckers(List> stateCheckers) - { - return StateCheckerSerializer.Serialize(stateCheckers); } - + protected virtual string SerializeProviders(ICollection providers) { return providers.Any() ? providers.JoinAsString(",") : null; } + + protected virtual string SerializeStateCheckers(List> stateCheckers) + { + return StateCheckerSerializer.Serialize(stateCheckers); + } } \ No newline at end of file From eb145d2198c4207f915dc0855b5ebf7c6c971349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 21 Aug 2022 11:42:19 +0300 Subject: [PATCH 63/70] Use ILocalizableStringSerializer while saving/getting permissions --- ...DynamicPermissionDefinitionStoreInMemoryCache.cs | 11 ++++++++--- .../PermissionDefinitionSerializer.cs | 13 ++++++------- .../PermissionDefinitionSerializer_Tests.cs | 7 ++++--- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs index 185d1c6fee..3b09c922dc 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -19,14 +19,19 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : protected IDictionary PermissionGroupDefinitions { get; } protected IDictionary PermissionDefinitions { get; } protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } + protected ILocalizableStringSerializer LocalizableStringSerializer { get; } public SemaphoreSlim SyncSemaphore { get; } = new(1, 1); public DateTime? LastCheckTime { get; set; } - public DynamicPermissionDefinitionStoreInMemoryCache(ISimpleStateCheckerSerializer stateCheckerSerializer) + public DynamicPermissionDefinitionStoreInMemoryCache( + ISimpleStateCheckerSerializer stateCheckerSerializer, + ILocalizableStringSerializer localizableStringSerializer) { StateCheckerSerializer = stateCheckerSerializer; + LocalizableStringSerializer = localizableStringSerializer; + PermissionGroupDefinitions = new Dictionary(); PermissionDefinitions = new Dictionary(); } @@ -44,7 +49,7 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : { var permissionGroup = context.AddGroup( permissionGroupRecord.Name, - new FixedLocalizableString(permissionGroupRecord.DisplayName) //TODO: Consider localization + LocalizableStringSerializer.Deserialize(permissionGroupRecord.DisplayName) ); PermissionGroupDefinitions[permissionGroup.Name] = permissionGroup; @@ -87,7 +92,7 @@ public class DynamicPermissionDefinitionStoreInMemoryCache : { var permission = permissionContainer.AddPermission( permissionRecord.Name, - new FixedLocalizableString(permissionRecord.DisplayName), + LocalizableStringSerializer.Deserialize(permissionRecord.DisplayName), permissionRecord.MultiTenancySide, permissionRecord.IsEnabled ); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs index 49104c85b6..8e63342502 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.Linq; using System.Threading.Tasks; -using Microsoft.Extensions.Localization; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; @@ -16,16 +15,16 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I { protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } protected IGuidGenerator GuidGenerator { get; } - protected IStringLocalizerFactory StringLocalizerFactory { get; } + protected ILocalizableStringSerializer LocalizableStringSerializer { get; } public PermissionDefinitionSerializer( IGuidGenerator guidGenerator, - IStringLocalizerFactory stringLocalizerFactory, - ISimpleStateCheckerSerializer stateCheckerSerializer) + ISimpleStateCheckerSerializer stateCheckerSerializer, + ILocalizableStringSerializer localizableStringSerializer) { StateCheckerSerializer = stateCheckerSerializer; + LocalizableStringSerializer = localizableStringSerializer; GuidGenerator = guidGenerator; - StringLocalizerFactory = stringLocalizerFactory; } public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> @@ -54,7 +53,7 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I var permissionGroupRecord = new PermissionGroupDefinitionRecord( GuidGenerator.Create(), permissionGroup.Name, - permissionGroup.DisplayName.Localize(StringLocalizerFactory) + LocalizableStringSerializer.Serialize(permissionGroup.DisplayName) ); foreach (var property in permissionGroup.Properties) @@ -77,7 +76,7 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I permissionGroup?.Name, permission.Name, permission.Parent?.Name, - permission.DisplayName.Localize(StringLocalizerFactory), + LocalizableStringSerializer.Serialize(permission.DisplayName), permission.IsEnabled, permission.MultiTenancySide, SerializeProviders(permission.Providers), diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs index eed7a3435a..1e7c04580c 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -8,6 +8,7 @@ using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; +using Volo.Abp.PermissionManagement.Localization; using Xunit; namespace Volo.Abp.PermissionManagement; @@ -36,7 +37,7 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase //Assert permissionGroupRecord.Name.ShouldBe("Group1"); - permissionGroupRecord.DisplayName.ShouldBe("Group one"); + permissionGroupRecord.DisplayName.ShouldBe("F:Group one"); permissionGroupRecord.GetProperty("CustomProperty1").ShouldBe("CustomValue1"); } @@ -49,7 +50,7 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase var group1 = CreatePermissionGroup1(context); var permission1 = group1.AddPermission( "Permission1", - new FixedLocalizableString("Permission one"), + new LocalizableString(typeof(AbpPermissionManagementResource), "Permission1"), MultiTenancySides.Tenant ) .WithProviders("ProviderA", "ProviderB") @@ -70,7 +71,7 @@ public class PermissionDefinitionSerializer_Tests : PermissionTestBase permissionRecord.Name.ShouldBe("Permission1"); permissionRecord.GroupName.ShouldBe("Group1"); - permissionRecord.DisplayName.ShouldBe("Permission one"); + permissionRecord.DisplayName.ShouldBe("L:AbpPermissionManagement,Permission1"); permissionRecord.GetProperty("CustomProperty2").ShouldBe("CustomValue2"); permissionRecord.Providers.ShouldBe("ProviderA,ProviderB"); permissionRecord.MultiTenancySide.ShouldBe(MultiTenancySides.Tenant); From bc0dc6dd42f0f90a7812b48645905c195467830c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 21 Aug 2022 11:57:20 +0300 Subject: [PATCH 64/70] Tolerate if IHostApplicationLifetime is not available --- .../AbpPermissionManagementDomainModule.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index 72d2bb9eef..feb11fdee5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -39,7 +40,8 @@ public class AbpPermissionManagementDomainModule : AbpModule private static void SaveStaticPermissionsToDatabase(ApplicationInitializationContext context) { var rootServiceProvider = context.ServiceProvider.GetRequiredService(); - var hostApplicationLifetime = context.ServiceProvider.GetRequiredService(); + var hostApplicationLifetime = context.ServiceProvider.GetService(); + var cancellationToken = hostApplicationLifetime?.ApplicationStopping ?? CancellationToken.None; Task.Run(async () => { @@ -48,7 +50,7 @@ public class AbpPermissionManagementDomainModule : AbpModule try { - using (cancellationTokenProvider.Use(hostApplicationLifetime.ApplicationStopping)) + using (cancellationTokenProvider.Use(cancellationToken)) { await Policy .Handle() From e260798b0dfd34e439ba565412d2041459156411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 21 Aug 2022 12:13:37 +0300 Subject: [PATCH 65/70] PermissionManagementModal should update localizations on UI --- .../PermissionManagementModal.razor.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs index b477de008d..36358c1b95 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Blazor/Components/PermissionManagementModal.razor.cs @@ -4,7 +4,9 @@ using System.Linq; using System.Threading.Tasks; using Blazorise; using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Components.Web.Configuration; +using Volo.Abp.Localization; using Volo.Abp.PermissionManagement.Localization; namespace Volo.Abp.PermissionManagement.Blazor.Components; @@ -14,6 +16,8 @@ public partial class PermissionManagementModal [Inject] protected IPermissionAppService PermissionAppService { get; set; } [Inject] protected ICurrentApplicationConfigurationCacheResetService CurrentApplicationConfigurationCacheResetService { get; set; } + [Inject] protected IOptions LocalizationOptions { get; set; } + protected Modal _modal; protected string _providerName; @@ -80,6 +84,8 @@ public partial class PermissionManagementModal var result = await PermissionAppService.GetAsync(_providerName, _providerKey); + UpdateLocalizations(result); + _entityDisplayName = entityDisplayName ?? result.EntityDisplayName; _groups = result.Groups; @@ -246,4 +252,47 @@ public partial class PermissionManagementModal eventArgs.Cancel = eventArgs.CloseReason == CloseReason.FocusLostClosing; return Task.CompletedTask; } + + protected virtual void UpdateLocalizations(GetPermissionListResultDto result) + { + foreach (var group in result.Groups) + { + group.DisplayName = Localize( + group.DisplayNameKey, + group.DisplayNameResource, + group.DisplayName + ); + + foreach (var permission in group.Permissions) + { + permission.DisplayName = Localize( + permission.DisplayNameKey, + permission.DisplayNameResource, + permission.DisplayName + ); + } + } + } + + protected virtual string Localize(string key, string resourceName, string fallbackValue) + { + if (key.IsNullOrEmpty() || resourceName.IsNullOrEmpty()) + { + return fallbackValue; + } + + var resource = LocalizationOptions.Value.Resources.GetOrNull(resourceName); + if (resource == null) + { + return fallbackValue; + } + + var result = new LocalizableString(resource.ResourceType, key).Localize(StringLocalizerFactory); + if (result.ResourceNotFound) + { + return fallbackValue; + } + + return result.Value; + } } From 41ba0aba7cd5f57818fc8070066274f9673b655f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 21 Aug 2022 12:38:17 +0300 Subject: [PATCH 66/70] Precache dynamic permission and refactor AbpPermissionManagementDomainModule class. --- .../AbpPermissionManagementDomainModule.cs | 133 +++++++++++++----- .../DynamicPermissionDefinitionStore.cs | 73 +++++----- 2 files changed, 138 insertions(+), 68 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs index feb11fdee5..1e05590176 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/AbpPermissionManagementDomainModule.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Polly; using Volo.Abp.Authorization; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain; @@ -23,62 +24,124 @@ namespace Volo.Abp.PermissionManagement; [DependsOn(typeof(AbpJsonModule))] public class AbpPermissionManagementDomainModule : AbpModule { + private readonly CancellationTokenSource _cancellationTokenSource = new(); + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) { - if (context + InitializeDynamicPermissions(context); + return Task.CompletedTask; + } + + public override Task OnApplicationShutdownAsync(ApplicationShutdownContext context) + { + _cancellationTokenSource.Cancel(); + return Task.CompletedTask; + } + + private void InitializeDynamicPermissions(ApplicationInitializationContext context) + { + var options = context .ServiceProvider .GetRequiredService>() - .Value - .SaveStaticPermissionsToDatabase) + .Value; + + if (!options.SaveStaticPermissionsToDatabase && !options.IsDynamicPermissionStoreEnabled) { - SaveStaticPermissionsToDatabase(context); + return; } - return Task.CompletedTask; - } - - private static void SaveStaticPermissionsToDatabase(ApplicationInitializationContext context) - { var rootServiceProvider = context.ServiceProvider.GetRequiredService(); - var hostApplicationLifetime = context.ServiceProvider.GetService(); - var cancellationToken = hostApplicationLifetime?.ApplicationStopping ?? CancellationToken.None; Task.Run(async () => { using var scope = rootServiceProvider.CreateScope(); + var applicationLifetime = scope.ServiceProvider.GetService(); var cancellationTokenProvider = scope.ServiceProvider.GetRequiredService(); - + var cancellationToken = applicationLifetime?.ApplicationStopping ?? _cancellationTokenSource.Token; + try { using (cancellationTokenProvider.Use(cancellationToken)) { - await Policy - .Handle() - .WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) - .ExecuteAsync(async _ => - { - try - { - // ReSharper disable once AccessToDisposedClosure - await scope - .ServiceProvider - .GetRequiredService() - .SaveAsync(); - } - catch (Exception ex) - { - // ReSharper disable once AccessToDisposedClosure - scope.ServiceProvider - .GetService>()? - .LogException(ex); - - throw; // Polly will catch it - } - }, cancellationTokenProvider.Token); + if (cancellationTokenProvider.Token.IsCancellationRequested) + { + return; + } + + await SaveStaticPermissionsToDatabaseAsync(options, scope, cancellationTokenProvider); + + if (cancellationTokenProvider.Token.IsCancellationRequested) + { + return; + } + + await PreCacheDynamicPermissionsAsync(options, scope); } } // ReSharper disable once EmptyGeneralCatchClause (No need to log since it is logged above) catch { } }); } + + private async static Task SaveStaticPermissionsToDatabaseAsync( + PermissionManagementOptions options, + IServiceScope scope, + ICancellationTokenProvider cancellationTokenProvider) + { + if (!options.SaveStaticPermissionsToDatabase) + { + return; + } + + await Policy + .Handle() + .WaitAndRetryAsync(8, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) * 10)) + .ExecuteAsync(async _ => + { + try + { + // ReSharper disable once AccessToDisposedClosure + await scope + .ServiceProvider + .GetRequiredService() + .SaveAsync(); + } + catch (Exception ex) + { + // ReSharper disable once AccessToDisposedClosure + scope.ServiceProvider + .GetService>()? + .LogException(ex); + + throw; // Polly will catch it + } + }, cancellationTokenProvider.Token); + } + + private async static Task PreCacheDynamicPermissionsAsync(PermissionManagementOptions options, IServiceScope scope) + { + if (!options.IsDynamicPermissionStoreEnabled) + { + return; + } + + try + { + // Pre-cache permissions, so first request doesn't wait + await scope + .ServiceProvider + .GetRequiredService() + .GetGroupsAsync(); + } + catch (Exception ex) + { + // ReSharper disable once AccessToDisposedClosure + scope + .ServiceProvider + .GetService>()? + .LogException(ex); + + throw; // It will be cached in InitializeDynamicPermissions + } + } } \ No newline at end of file diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index 2a507c2ab5..f2e73cefc0 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; @@ -49,9 +50,12 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor { return null; } - - await EnsureCacheIsUptoDateAsync(); - return StoreCache.GetPermissionOrNull(name); + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissionOrNull(name); + } } public virtual async Task> GetPermissionsAsync() @@ -60,9 +64,12 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor { return Array.Empty(); } - - await EnsureCacheIsUptoDateAsync(); - return StoreCache.GetPermissions(); + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissions().ToImmutableList(); + } } public virtual async Task> GetGroupsAsync() @@ -71,38 +78,38 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor { return Array.Empty(); } - - await EnsureCacheIsUptoDateAsync(); - return StoreCache.GetGroups(); - } - private async Task EnsureCacheIsUptoDateAsync() - { using (await StoreCache.SyncSemaphore.LockAsync()) { - if (StoreCache.LastCheckTime.HasValue && - DateTime.Now.Subtract(StoreCache.LastCheckTime.Value).TotalSeconds < 30) - { - /* We get the latest permission with a small delay for optimization */ - return; - } - - var stampInDistributedCache = await GetOrSetStampInDistributedCache(); - - if (stampInDistributedCache == StoreCache.CacheStamp) - { - StoreCache.LastCheckTime = DateTime.Now; - return; - } - - await UpdateInMemoryStoreCache(); + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetGroups().ToImmutableList(); + } + } - StoreCache.CacheStamp = stampInDistributedCache; + protected virtual async Task EnsureCacheIsUptoDateAsync() + { + if (StoreCache.LastCheckTime.HasValue && + DateTime.Now.Subtract(StoreCache.LastCheckTime.Value).TotalSeconds < 30) + { + /* We get the latest permission with a small delay for optimization */ + return; + } + + var stampInDistributedCache = await GetOrSetStampInDistributedCache(); + + if (stampInDistributedCache == StoreCache.CacheStamp) + { StoreCache.LastCheckTime = DateTime.Now; + return; } + + await UpdateInMemoryStoreCache(); + + StoreCache.CacheStamp = stampInDistributedCache; + StoreCache.LastCheckTime = DateTime.Now; } - private async Task UpdateInMemoryStoreCache() + protected virtual async Task UpdateInMemoryStoreCache() { var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); var permissionRecords = await PermissionRepository.GetListAsync(); @@ -110,7 +117,7 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); } - private async Task GetOrSetStampInDistributedCache() + protected virtual async Task GetOrSetStampInDistributedCache() { var cacheKey = GetCommonStampCacheKey(); @@ -152,12 +159,12 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor return stampInDistributedCache; } - private string GetCommonStampCacheKey() + protected virtual string GetCommonStampCacheKey() { return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; } - private string GetCommonDistributedLockKey() + protected virtual string GetCommonDistributedLockKey() { return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; } From 3bd15f80a1fd63a56073fa6c33858e941e9cf2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 21 Aug 2022 14:41:21 +0300 Subject: [PATCH 67/70] Comment update. --- .../Volo/Abp/PermissionManagement/StaticPermissionSaver.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs index 30f88e8c2d..5754031509 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -55,8 +55,6 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc [UnitOfWork] public virtual async Task SaveAsync() { - /* TODO: We may double check and lock for optimization - */ await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( GetApplicationDistributedLockKey() ); @@ -69,7 +67,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc /* NOTE: This can be further optimized by using 4 cache values for: * Groups, permissions, deleted groups and deleted permissions. - * But the code would be more complex. + * But the code would be more complex. This is enough for now. */ var cacheKey = GetApplicationHashCacheKey(); From 90e03c5303b7a64f6ac75847f0c2213855c6385b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 21 Aug 2022 16:27:35 +0300 Subject: [PATCH 68/70] Set AbpAuditingOptions.ApplicationName by default From the global application name. --- .../Volo/Abp/Auditing/AbpAuditingModule.cs | 17 +++++++++++++- .../Abp/Auditing/AbpAuditingOptions_Tests.cs | 23 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingOptions_Tests.cs diff --git a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs index bb3f104ce4..b6527f10c8 100644 --- a/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs +++ b/framework/src/Volo.Abp.Auditing/Volo/Abp/Auditing/AbpAuditingModule.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Data; using Volo.Abp.Json; using Volo.Abp.Modularity; @@ -24,4 +26,17 @@ public class AbpAuditingModule : AbpModule { context.Services.OnRegistred(AuditingInterceptorRegistrar.RegisterIfNeeded); } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var applicationName = context.Services.GetApplicationName(); + + if (!applicationName.IsNullOrEmpty()) + { + Configure(options => + { + options.ApplicationName = applicationName; + }); + } + } } diff --git a/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingOptions_Tests.cs b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingOptions_Tests.cs new file mode 100644 index 0000000000..6853046241 --- /dev/null +++ b/framework/test/Volo.Abp.Auditing.Tests/Volo/Abp/Auditing/AbpAuditingOptions_Tests.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Options; +using Shouldly; +using Xunit; + +namespace Volo.Abp.Auditing; + +public class AbpAuditingOptions_Tests : AbpAuditingTestBase +{ + private const string ApplicationName = "TEST_APP_NAME"; + + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + base.SetAbpApplicationCreationOptions(options); + options.ApplicationName = ApplicationName; + } + + [Fact] + public void Should_Set_Application_Name_From_Global_Application_Name_By_Default() + { + var options = GetRequiredService>().Value; + options.ApplicationName.ShouldBe(ApplicationName); + } +} \ No newline at end of file From 55f83350d7c788899e250683db440c1c8a9e43cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 24 Aug 2022 18:43:30 +0300 Subject: [PATCH 69/70] Fix SimpleStateCheckerSerializerExtensions --- .../SimpleStateCheckerSerializerExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs index 1e4d272379..3594261741 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs @@ -82,7 +82,7 @@ public static class SimpleStateCheckerSerializerExtensions throw new AbpException("JSON value is not an array of objects: " + value); } - checkers[i] = serializer.Deserialize(jsonObject, state); + checkers.Add(serializer.Deserialize(jsonObject, state)); } return checkers.Where(x => x != null).ToArray(); From 6bb3ec3c7628a249acbc23788e6debd57854ed8a Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 25 Aug 2022 09:31:15 +0800 Subject: [PATCH 70/70] Update migrations of templates. --- ....cs => 20220825012458_Initial.Designer.cs} | 83 +++++++++- ...0_Initial.cs => 20220825012458_Initial.cs} | 57 +++++++ .../MyProjectNameDbContextModelSnapshot.cs | 81 ++++++++++ ....cs => 20220825012635_Initial.Designer.cs} | 83 +++++++++- ...9_Initial.cs => 20220825012635_Initial.cs} | 57 +++++++ .../MyProjectNameDbContextModelSnapshot.cs | 81 ++++++++++ ....cs => 20220825012450_Initial.Designer.cs} | 83 +++++++++- ...9_Initial.cs => 20220825012450_Initial.cs} | 57 +++++++ .../MyProjectNameDbContextModelSnapshot.cs | 81 ++++++++++ .../20220825012254_Initial.Designer.cs} | 150 ++++++++++++++++-- .../Migrations/20220825012254_Initial.cs} | 86 ++++++++++ .../MyProjectNameDbContextModelSnapshot.cs | 81 ++++++++++ .../20220825012920_Initial.Designer.cs} | 150 +++++++++++------- .../Migrations/20220825012920_Initial.cs} | 86 ++++++---- .../AuthServerDbContextModelSnapshot.cs | 81 ++++++++++ ....cs => 20220825013015_Initial.Designer.cs} | 83 +++++++++- ...8_Initial.cs => 20220825013015_Initial.cs} | 57 +++++++ .../UnifiedDbContextModelSnapshot.cs | 81 ++++++++++ ....cs => 20220825013032_Initial.Designer.cs} | 83 +++++++++- ...9_Initial.cs => 20220825013032_Initial.cs} | 57 +++++++ .../UnifiedDbContextModelSnapshot.cs | 81 ++++++++++ 21 files changed, 1636 insertions(+), 103 deletions(-) rename templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/{20220617083820_Initial.Designer.cs => 20220825012458_Initial.Designer.cs} (95%) rename templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/{20220617083820_Initial.cs => 20220825012458_Initial.cs} (94%) rename templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/{20220617083539_Initial.Designer.cs => 20220825012635_Initial.Designer.cs} (95%) rename templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/{20220617083539_Initial.cs => 20220825012635_Initial.cs} (94%) rename templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/{20220617083649_Initial.Designer.cs => 20220825012450_Initial.Designer.cs} (95%) rename templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/{20220617083649_Initial.cs => 20220825012450_Initial.cs} (94%) rename templates/{module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.Designer.cs => app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.Designer.cs} (92%) rename templates/{module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.cs => app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.cs} (91%) rename templates/{app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.Designer.cs => module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.Designer.cs} (95%) rename templates/{app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.cs => module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.cs} (95%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/{20220617083658_Initial.Designer.cs => 20220825013015_Initial.Designer.cs} (94%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/{20220617083658_Initial.cs => 20220825013015_Initial.cs} (93%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20220617083659_Initial.Designer.cs => 20220825013032_Initial.Designer.cs} (94%) rename templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/{20220617083659_Initial.cs => 20220825013032_Initial.cs} (93%) diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.Designer.cs similarity index 95% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.Designer.cs index 9e1a8f9cd8..5347dc149d 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083820_Initial")] + [Migration("20220825012458_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -1273,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.cs similarity index 94% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.cs index 85d36d8b57..13ecbb5be7 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220617083820_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/20220825012458_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -714,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -850,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs index 0a32c8664e..d6c92decad 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.Designer.cs similarity index 95% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.Designer.cs index 5b55ca75a9..0c525e8471 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Host.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083539_Initial")] + [Migration("20220825012635_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -1273,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.cs similarity index 94% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.cs index 29cc53b046..8342507d18 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220617083539_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/20220825012635_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Host.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -714,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Host.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -850,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Host.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs index 2597920679..7360423342 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.Designer.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.Designer.cs similarity index 95% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.Designer.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.Designer.cs index 213ce02572..94f77b9938 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.Designer.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Mvc.Migrations { [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083649_Initial")] + [Migration("20220825012450_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -1273,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.cs similarity index 94% rename from templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.cs rename to templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.cs index 2a30fba759..df71202963 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220617083649_Initial.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/20220825012450_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -714,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -850,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs index 350f086968..80d24ed8d2 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Mvc.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.Designer.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.Designer.cs similarity index 92% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.Designer.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.Designer.cs index ae32d5daa9..41c49a2e4d 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.Designer.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.Designer.cs @@ -12,8 +12,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(AuthServerDbContext))] - [Migration("20220617083652_Initial")] + [DbContext(typeof(MyProjectNameDbContext))] + [Migration("20220825012254_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -288,6 +288,64 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges", (string)null); }); + modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasMaxLength(40) + .HasColumnType("nvarchar(40)") + .HasColumnName("ConcurrencyStamp"); + + b.Property("CreationTime") + .HasColumnType("datetime2") + .HasColumnName("CreationTime"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("IsAbandoned") + .ValueGeneratedOnAdd() + .HasColumnType("bit") + .HasDefaultValue(false); + + b.Property("JobArgs") + .IsRequired() + .HasMaxLength(1048576) + .HasColumnType("nvarchar(max)"); + + b.Property("JobName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("LastTryTime") + .HasColumnType("datetime2"); + + b.Property("NextTryTime") + .HasColumnType("datetime2"); + + b.Property("Priority") + .ValueGeneratedOnAdd() + .HasColumnType("tinyint") + .HasDefaultValue((byte)15); + + b.Property("TryCount") + .ValueGeneratedOnAdd() + .HasColumnType("smallint") + .HasDefaultValue((short)0); + + b.HasKey("Id"); + + b.HasIndex("IsAbandoned", "NextTryTime"); + + b.ToTable("AbpBackgroundJobs", (string)null); + }); + modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => { b.Property("Id") @@ -324,7 +382,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -371,7 +428,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("SourceTenantId") @@ -398,7 +454,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -475,7 +530,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Action") @@ -550,7 +604,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("AccessFailedCount") @@ -834,7 +887,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Code") @@ -1273,6 +1325,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1307,6 +1412,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") @@ -1343,7 +1476,6 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.cs similarity index 91% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.cs rename to templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.cs index cbc01e3dfe..8ddcfae69e 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220617083652_Initial.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220825012254_Initial.cs @@ -43,6 +43,27 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpBackgroundJobs", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + JobName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + JobArgs = table.Column(type: "nvarchar(max)", maxLength: 1048576, nullable: false), + TryCount = table.Column(type: "smallint", nullable: false, defaultValue: (short)0), + CreationTime = table.Column(type: "datetime2", nullable: false), + NextTryTime = table.Column(type: "datetime2", nullable: false), + LastTryTime = table.Column(type: "datetime2", nullable: true), + IsAbandoned = table.Column(type: "bit", nullable: false, defaultValue: false), + Priority = table.Column(type: "tinyint", nullable: false, defaultValue: (byte)15), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -137,6 +158,40 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -663,6 +718,11 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); + migrationBuilder.CreateIndex( + name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", + table: "AbpBackgroundJobs", + columns: new[] { "IsAbandoned", "NextTryTime" }); + migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -714,6 +774,23 @@ namespace MyCompanyName.MyProjectName.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -832,6 +909,9 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); + migrationBuilder.DropTable( + name: "AbpBackgroundJobs"); + migrationBuilder.DropTable( name: "AbpClaimTypes"); @@ -850,6 +930,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs index 781691a3d2..ce8d020786 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/MyProjectNameDbContextModelSnapshot.cs @@ -1323,6 +1323,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1357,6 +1410,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.Designer.cs similarity index 95% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.Designer.cs index 1ea724aa5b..6f31dccc25 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.Designer.cs @@ -12,8 +12,8 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { - [DbContext(typeof(MyProjectNameDbContext))] - [Migration("20220617083228_Initial")] + [DbContext(typeof(AuthServerDbContext))] + [Migration("20220825012920_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -288,64 +288,6 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpEntityPropertyChanges", (string)null); }); - modelBuilder.Entity("Volo.Abp.BackgroundJobs.BackgroundJobRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasMaxLength(40) - .HasColumnType("nvarchar(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("CreationTime") - .HasColumnType("datetime2") - .HasColumnName("CreationTime"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("IsAbandoned") - .ValueGeneratedOnAdd() - .HasColumnType("bit") - .HasDefaultValue(false); - - b.Property("JobArgs") - .IsRequired() - .HasMaxLength(1048576) - .HasColumnType("nvarchar(max)"); - - b.Property("JobName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("LastTryTime") - .HasColumnType("datetime2"); - - b.Property("NextTryTime") - .HasColumnType("datetime2"); - - b.Property("Priority") - .ValueGeneratedOnAdd() - .HasColumnType("tinyint") - .HasDefaultValue((byte)15); - - b.Property("TryCount") - .ValueGeneratedOnAdd() - .HasColumnType("smallint") - .HasDefaultValue((short)0); - - b.HasKey("Id"); - - b.HasIndex("IsAbandoned", "NextTryTime"); - - b.ToTable("AbpBackgroundJobs", (string)null); - }); - modelBuilder.Entity("Volo.Abp.FeatureManagement.FeatureValue", b => { b.Property("Id") @@ -382,6 +324,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityClaimType", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -428,6 +371,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityLinkUser", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("SourceTenantId") @@ -454,6 +398,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityRole", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") @@ -530,6 +475,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentitySecurityLog", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Action") @@ -604,6 +550,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.IdentityUser", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("AccessFailedCount") @@ -887,6 +834,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.Identity.OrganizationUnit", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Code") @@ -1325,6 +1273,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1359,6 +1360,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") @@ -1395,6 +1424,7 @@ namespace MyCompanyName.MyProjectName.Migrations modelBuilder.Entity("Volo.Abp.TenantManagement.Tenant", b => { b.Property("Id") + .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("ConcurrencyStamp") diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.cs similarity index 95% rename from templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.cs index 55ae609199..e2dfaa2f6f 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/Migrations/20220617083228_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/20220825012920_Initial.cs @@ -43,27 +43,6 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); }); - migrationBuilder.CreateTable( - name: "AbpBackgroundJobs", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - JobName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - JobArgs = table.Column(type: "nvarchar(max)", maxLength: 1048576, nullable: false), - TryCount = table.Column(type: "smallint", nullable: false, defaultValue: (short)0), - CreationTime = table.Column(type: "datetime2", nullable: false), - NextTryTime = table.Column(type: "datetime2", nullable: false), - LastTryTime = table.Column(type: "datetime2", nullable: true), - IsAbandoned = table.Column(type: "bit", nullable: false, defaultValue: false), - Priority = table.Column(type: "tinyint", nullable: false, defaultValue: (byte)15), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpBackgroundJobs", x => x.Id); - }); - migrationBuilder.CreateTable( name: "AbpClaimTypes", columns: table => new @@ -158,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -684,11 +697,6 @@ namespace MyCompanyName.MyProjectName.Migrations table: "AbpAuditLogs", columns: new[] { "TenantId", "UserId", "ExecutionTime" }); - migrationBuilder.CreateIndex( - name: "IX_AbpBackgroundJobs_IsAbandoned_NextTryTime", - table: "AbpBackgroundJobs", - columns: new[] { "IsAbandoned", "NextTryTime" }); - migrationBuilder.CreateIndex( name: "IX_AbpEntityChanges_AuditLogId", table: "AbpEntityChanges", @@ -740,6 +748,23 @@ namespace MyCompanyName.MyProjectName.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -858,9 +883,6 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpAuditLogActions"); - migrationBuilder.DropTable( - name: "AbpBackgroundJobs"); - migrationBuilder.DropTable( name: "AbpClaimTypes"); @@ -879,6 +901,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs index e483e20a49..4ba9b7daaa 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/Migrations/AuthServerDbContextModelSnapshot.cs @@ -1271,6 +1271,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("OpenIddictTokens", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -1305,6 +1358,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.Designer.cs similarity index 94% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.Designer.cs index da5ce77b3f..4a13126215 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20220617083658_Initial")] + [Migration("20220825013015_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -932,6 +932,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -966,6 +1019,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.cs similarity index 93% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.cs index f575db2142..be6fee4b31 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220617083658_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/20220825013015_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -581,6 +615,23 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -687,6 +738,12 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs index 7ef4a80da0..0ba27152ac 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/Migrations/UnifiedDbContextModelSnapshot.cs @@ -930,6 +930,59 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -964,6 +1017,34 @@ namespace MyCompanyName.MyProjectName.Blazor.Server.Host.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.Designer.cs similarity index 94% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.Designer.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.Designer.cs index e9f1df7c94..68cf3fe47f 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.Designer.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.Designer.cs @@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.Migrations { [DbContext(typeof(UnifiedDbContext))] - [Migration("20220617083659_Initial")] + [Migration("20220825013032_Initial")] partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -932,6 +932,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -966,6 +1019,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id") diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.cs similarity index 93% rename from templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.cs rename to templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.cs index b02029a8cd..7c0caa1baa 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220617083659_Initial.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/20220825013032_Initial.cs @@ -137,6 +137,40 @@ namespace MyCompanyName.MyProjectName.Migrations table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); }); + migrationBuilder.CreateTable( + name: "AbpPermissionGroups", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissionGroups", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AbpPermissions", + columns: table => new + { + Id = table.Column(type: "uniqueidentifier", nullable: false), + GroupName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), + ParentName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + DisplayName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + IsEnabled = table.Column(type: "bit", nullable: false), + MultiTenancySide = table.Column(type: "tinyint", nullable: false), + Providers = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), + StateCheckers = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AbpPermissions", x => x.Id); + }); + migrationBuilder.CreateTable( name: "AbpRoles", columns: table => new @@ -581,6 +615,23 @@ namespace MyCompanyName.MyProjectName.Migrations unique: true, filter: "[TenantId] IS NOT NULL"); + migrationBuilder.CreateIndex( + name: "IX_AbpPermissionGroups_Name", + table: "AbpPermissionGroups", + column: "Name", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_GroupName", + table: "AbpPermissions", + column: "GroupName"); + + migrationBuilder.CreateIndex( + name: "IX_AbpPermissions_Name", + table: "AbpPermissions", + column: "Name", + unique: true); + migrationBuilder.CreateIndex( name: "IX_AbpRoleClaims_RoleId", table: "AbpRoleClaims", @@ -687,6 +738,12 @@ namespace MyCompanyName.MyProjectName.Migrations migrationBuilder.DropTable( name: "AbpPermissionGrants"); + migrationBuilder.DropTable( + name: "AbpPermissionGroups"); + + migrationBuilder.DropTable( + name: "AbpPermissions"); + migrationBuilder.DropTable( name: "AbpRoleClaims"); diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs index 39b8871ef6..cb1236c39b 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/Migrations/UnifiedDbContextModelSnapshot.cs @@ -930,6 +930,59 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpOrganizationUnitRoles", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("GroupName") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("IsEnabled") + .HasColumnType("bit"); + + b.Property("MultiTenancySide") + .HasColumnType("tinyint"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("ParentName") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Providers") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("StateCheckers") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("GroupName"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissions", (string)null); + }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => { b.Property("Id") @@ -964,6 +1017,34 @@ namespace MyCompanyName.MyProjectName.Migrations b.ToTable("AbpPermissionGrants", (string)null); }); + modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGroupDefinitionRecord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uniqueidentifier"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("ExtraProperties") + .HasColumnType("nvarchar(max)") + .HasColumnName("ExtraProperties"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("AbpPermissionGroups", (string)null); + }); + modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => { b.Property("Id")