Browse Source

Update changed permission groups

pull/13644/head
Halil İbrahim Kalkan 4 years ago
parent
commit
acd1660eca
  1. 2
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs
  2. 4
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs
  3. 43
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs
  4. 6
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs
  5. 138
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs
  6. 35
      modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs

2
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs

@ -14,6 +14,6 @@ public interface IPermissionDefinitionSerializer
Task<PermissionGroupDefinitionRecord> SerializeAsync(
PermissionGroupDefinition permissionGroup);
Task<(List<PermissionGroupDefinitionRecord>, List<PermissionDefinitionRecord>)>
Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])>
SerializeAsync(IEnumerable<PermissionGroupDefinition> permissionGroups);
}

4
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<PermissionGroupDefinitionRecord>, List<PermissionDefinitionRecord>)>
public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])>
SerializeAsync(IEnumerable<PermissionGroupDefinition> permissionGroups)
{
var permissionGroupRecords = new List<PermissionGroupDefinitionRecord>();
@ -97,7 +97,7 @@ public class PermissionDefinitionSerializer : IPermissionDefinitionSerializer, I
}
}
return (permissionGroupRecords, permissionRecords);
return (permissionGroupRecords.ToArray(), permissionRecords.ToArray());
}
public Task<PermissionGroupDefinition> DeserializeAsync(PermissionGroupDefinitionRecord permissionGroupRecord)

43
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs

@ -30,4 +30,47 @@ public class PermissionGroupDefinitionRecord : BasicAggregateRoot<Guid>, 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);
}
}
}
}

6
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs

@ -8,10 +8,16 @@ public class PermissionManagementOptions
public ITypeList<IPermissionManagementProvider> ManagementProviders { get; }
public Dictionary<string, string> ProviderPolicies { get; }
public HashSet<string> DeletedPermissions { get; }
public HashSet<string> DeletedPermissionGroups { get; }
public PermissionManagementOptions()
{
ManagementProviders = new TypeList<IPermissionManagementProvider>();
ProviderPolicies = new Dictionary<string, string>();
DeletedPermissions = new HashSet<string>();
DeletedPermissionGroups = new HashSet<string>();
}
}

138
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<AbpDistributedCacheOptions> cacheOptions,
IApplicationNameAccessor applicationNameAccessor,
IAbpDistributedLock distributedLock,
IOptions<PermissionManagementOptions> 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<PermissionGroupDefinitionRecord>();
var changedRecords = new List<PermissionGroupDefinitionRecord>();
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<string> deletedPermissionGroups,
IEnumerable<string> 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();
}
}

35
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<FixedLocalizableString>();
permission.DisplayName.As<FixedLocalizableString>().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<RequireGlobalFeaturesSimpleStateChecker<PermissionDefinition>>();
}
private static PermissionGroupDefinition CreatePermissionGroup1(
IPermissionDefinitionContext context)

Loading…
Cancel
Save