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] 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