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..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.GetOrNull(policyName) != null) + if (await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && + await _permissionDefinitionManager.GetOrNullAsync(policyName) != null) { abpPolicyNames.Add(policyName); } @@ -214,9 +215,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.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/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/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/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.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/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..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 //TODO: Consider to make possible a group have sub groups +public class PermissionGroupDefinition : ICanAddChildPermission { /// /// 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,19 +39,17 @@ 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(); } public virtual PermissionDefinition AddPermission( - string name, + [NotNull] string name, ILocalizableString displayName = null, MultiTenancySides multiTenancySide = MultiTenancySides.Both, bool isEnabled = true) 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/AuthenticatedSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..2a23b5bfcd --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AuthenticatedSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,38 @@ +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.Authorization.Permissions; + +public class AuthenticatedSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "A"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireAuthenticatedSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName + }; + + return jsonObject.ToJsonString(); + } + + public ISimpleStateChecker Deserialize(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers + { + if (jsonObject["T"]?.ToString() != CheckerShortName) + { + return null; + } + + return new RequireAuthenticatedSimpleStateChecker(); + } +} \ No newline at end of file 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/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/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/PermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs index fec8771afa..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,8 +43,12 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency { Check.NotNull(name, nameof(name)); - var permission = PermissionDefinitionManager.Get(name); - + var permission = await PermissionDefinitionManager.GetOrNullAsync(name); + if (permission == null) + { + return false; + } + if (!permission.IsEnabled) { return false; @@ -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 = PermissionDefinitionManager.Get(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/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs index 7f4de3c767..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 @@ -1,47 +1,27 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Authorization.Permissions; -public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingletonDependency +public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransientDependency { - 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; + private readonly IStaticPermissionDefinitionStore _staticStore; + private readonly IDynamicPermissionDefinitionStore _dynamicStore; public PermissionDefinitionManager( - IOptions options, - IServiceProvider serviceProvider) + IStaticPermissionDefinitionStore staticStore, + IDynamicPermissionDefinitionStore dynamicStore) { - _serviceProvider = serviceProvider; - Options = options.Value; - - _lazyPermissionDefinitions = new Lazy>( - CreatePermissionDefinitions, - isThreadSafe: true - ); - - _lazyPermissionGroupDefinitions = new Lazy>( - CreatePermissionGroupDefinitions, - isThreadSafe: true - ); + _staticStore = staticStore; + _dynamicStore = dynamicStore; } - 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) { throw new AbpException("Undefined permission: " + name); @@ -50,82 +30,41 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ISingle return permission; } - public virtual PermissionDefinition GetOrNull(string name) + public virtual async Task GetOrNullAsync(string name) { Check.NotNull(name, nameof(name)); - return PermissionDefinitions.GetOrDefault(name); - } - - public virtual IReadOnlyList GetPermissions() - { - return PermissionDefinitions.Values.ToImmutableList(); - } - - public IReadOnlyList GetGroups() - { - return 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; + return await _staticStore.GetOrNullAsync(name) ?? + await _dynamicStore.GetOrNullAsync(name); } - protected virtual void AddPermissionToDictionaryRecursively( - Dictionary permissions, - PermissionDefinition permission) + public virtual async Task> GetPermissionsAsync() { - 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); - } + 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(); } - protected virtual Dictionary CreatePermissionGroupDefinitions() + public async Task> GetGroupsAsync() { - 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; - } + 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 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.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 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..72ce661ed5 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..87ddf14c1b 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,8 +43,11 @@ public abstract class AbpApplicationBase : IAbpApplication var options = new AbpApplicationCreationOptions(services); optionsAction?.Invoke(options); + + ApplicationName = options.ApplicationName; services.AddSingleton(this); + services.AddSingleton(this); services.AddSingleton(this); services.AddCoreServices(); 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/DependencyInjection/IRootServiceProviderAccessor.cs b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs new file mode 100644 index 0000000000..8a3c1d09a5 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/IRootServiceProviderAccessor.cs @@ -0,0 +1,14 @@ +using System; + +namespace Volo.Abp.DependencyInjection; + +/// +/// 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 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/IAbpApplication.cs b/framework/src/Volo.Abp.Core/Volo/Abp/IAbpApplication.cs index 2fb66b735f..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,7 +26,7 @@ public interface IAbpApplication : IModuleContainer, IDisposable /// This can not be used before initialize the application. /// IServiceProvider ServiceProvider { get; } - + /// /// Calls the Pre/Post/ConfigureServicesAsync methods of the modules. /// If you use this method, you must have set the @@ -40,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/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..ffbed53cf7 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/ISimpleStateCheckerSerializer.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Nodes; + +namespace Volo.Abp.SimpleStateChecking; + +public interface ISimpleStateCheckerSerializer +{ + public string Serialize(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers; + + 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 new file mode 100644 index 0000000000..d65c90eee6 --- /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, 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 new file mode 100644 index 0000000000..d5d931ffae --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializer.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Text.Json.Nodes; +using JetBrains.Annotations; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SimpleStateChecking; + +public class SimpleStateCheckerSerializer : + ISimpleStateCheckerSerializer, + ISingletonDependency +{ + 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(JsonObject jsonObject, TState state) + where TState : IHasSimpleStateCheckers + { + foreach (var contributor in _contributors) + { + var result = contributor.Deserialize(jsonObject, state); + 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..3594261741 --- /dev/null +++ b/framework/src/Volo.Abp.Core/Volo/Abp/SimpleStateChecking/SimpleStateCheckerSerializerExtensions.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Nodes; + +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: + var serializedChecker = serializer.Serialize(stateCheckers.Single()); + return serializedChecker != null + ? $"[{serializedChecker}]" + : null; + default: + var serializedCheckers = new List(stateCheckers.Count); + + foreach (var stateChecker in stateCheckers) + { + var serialized = serializer.Serialize(stateChecker); + if (serialized != null) + { + serializedCheckers.Add(serialized); + } + } + + return serializedCheckers.Any() + ? $"[{serializedCheckers.JoinAsString(",")}]" + : null; + } + } + + public static ISimpleStateChecker[] DeserializeArray( + this ISimpleStateCheckerSerializer serializer, + string value, + TState state) + 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); + } + + var checker = serializer.Deserialize(jsonObject, state); + if (checker == null) + { + return Array.Empty>(); + } + + return new[] { checker }; + } + + var checkers = new List>(); + + 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.Add(serializer.Deserialize(jsonObject, state)); + } + + return checkers.Where(x => x != null).ToArray(); + } +} \ No newline at end of file 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 c642e33667..eef5b396a2 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.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeaturesSimpleStateCheckerSerializerContributor.cs new file mode 100644 index 0000000000..58e2817139 --- /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, 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 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 new file mode 100644 index 0000000000..d4abc25403 --- /dev/null +++ b/framework/src/Volo.Abp.GlobalFeatures/Volo/Abp/GlobalFeatures/GlobalFeaturesSimpleStateCheckerSerializerContributor.cs @@ -0,0 +1,56 @@ +using System.Linq; +using System.Text.Json.Nodes; +using Volo.Abp.DependencyInjection; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.GlobalFeatures; + +public class GlobalFeaturesSimpleStateCheckerSerializerContributor : + ISimpleStateCheckerSerializerContributor, + ISingletonDependency +{ + public const string CheckerShortName = "G"; + + public string SerializeToJson(ISimpleStateChecker checker) + where TState : IHasSimpleStateCheckers + { + if (checker is not RequireGlobalFeaturesSimpleStateChecker globalFeaturesSimpleStateChecker) + { + return null; + } + + var jsonObject = new JsonObject { + ["T"] = CheckerShortName, + ["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, 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 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/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs b/framework/src/Volo.Abp.Localization.Abstractions/Volo/Abp/Localization/LocalizableString.cs index 61494d609e..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; @@ -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) 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..4cfd6e2f32 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizableStringSerializer.cs @@ -0,0 +1,69 @@ +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); + if (name.IsNullOrWhiteSpace()) + { + throw new AbpException("Invalid LocalizableString value: " + value); + } + + var resourceType = LocalizationOptions.Resources.GetOrNull(resourceName)?.ResourceType; + + return new LocalizableString( + resourceType, + name + ); + default: + return new FixedLocalizableString(value); + } + } +} \ No newline at end of file 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 [Flags] -public enum MultiTenancySides +public enum MultiTenancySides : byte { /// /// Tenant side. 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/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; 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 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 new file mode 100644 index 0000000000..0d84d167de --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AuthenticatedSimpleStateCheckerSerializerContributor_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, new MyState()); + + checker.ShouldBeOfType>(); + var globalFeaturesSimpleStateChecker = checker as RequireAuthenticatedSimpleStateChecker; + globalFeaturesSimpleStateChecker.ShouldNotBeNull(); + } + + private class MyState : IHasSimpleStateCheckers + { + public List> StateCheckers { get; } = new(); + } +} \ No newline at end of file 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..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 = PermissionDefinitionManager.Get("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 = PermissionDefinitionManager.Get("MyPermission2"); + var myPermission2 = await PermissionDefinitionManager.GetOrNullAsync("MyPermission2"); + myPermission2.ShouldNotBeNull(); (await StateCheckerManager.IsEnabledAsync(myPermission2)).ShouldBeFalse(); 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..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 @@ -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; @@ -142,4 +143,40 @@ 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); + + application.Initialize(); + + application.ServiceProvider + .GetRequiredService() + .ApplicationName + .ShouldBe(applicationName); + } + } + + [Fact] + public async Task Should_Resolve_Root_Service_Provider() + { + using (var application = await AbpApplicationFactory.CreateAsync()) + { + await application.InitializeAsync(); + + application + .ServiceProvider + .GetRequiredService() + .ShouldNotBeNull(); + } + } } 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..9791ac44bc --- /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, new MyState()); + + 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 new file mode 100644 index 0000000000..e0425775dc --- /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\":\"G\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + } + + [Fact] + public void Should_Deserialize_RequireGlobalFeaturesSimpleStateChecker() + { + var serializer = new GlobalFeaturesSimpleStateCheckerSerializerContributor(); + + var jsonObject = (JsonObject)JsonNode.Parse("{\"T\":\"G\",\"A\":true,\"N\":[\"FeatureA\",\"FeatureB\"]}"); + var checker = serializer.Deserialize(jsonObject, new MyState()); + + 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/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 { 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(); + } } 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, diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs index b608a69b54..12e4010f99 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGrantInfoDto.cs @@ -7,6 +7,10 @@ public class PermissionGrantInfoDto public string Name { get; set; } public string DisplayName { get; set; } + + public string DisplayNameKey { get; set; } + + public string DisplayNameResource { get; set; } public string ParentName { get; set; } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs index a138cd0451..b9cc6d5f90 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Application.Contracts/Volo/Abp/PermissionManagement/PermissionGroupDto.cs @@ -7,6 +7,10 @@ public class PermissionGroupDto public string Name { get; set; } public string DisplayName { get; set; } + + public string DisplayNameKey { get; set; } + + public string DisplayNameResource { get; set; } public List 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 d7d7f28820..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; @@ -43,14 +44,9 @@ 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 - { - 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.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; + } } 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..93b1b465c6 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain.Shared/Volo/Abp/PermissionManagement/PermissionDefinitionRecordConsts.cs @@ -0,0 +1,15 @@ +namespace Volo.Abp.PermissionManagement; + +public class PermissionDefinitionRecordConsts +{ + /// + /// Default value: 128 + /// + 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.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.Domain.csproj b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo.Abp.PermissionManagement.Domain.csproj index d9cc5a058f..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 @@ -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 6dff7bf663..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 @@ -1,11 +1,19 @@ -using System.Collections.Generic; +using System; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +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; using Volo.Abp.Json; using Volo.Abp.Modularity; +using Volo.Abp.Threading; namespace Volo.Abp.PermissionManagement; @@ -16,5 +24,124 @@ namespace Volo.Abp.PermissionManagement; [DependsOn(typeof(AbpJsonModule))] public class AbpPermissionManagementDomainModule : AbpModule { + private readonly CancellationTokenSource _cancellationTokenSource = new(); + + public override Task OnApplicationInitializationAsync(ApplicationInitializationContext 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; + + if (!options.SaveStaticPermissionsToDatabase && !options.IsDynamicPermissionStoreEnabled) + { + return; + } + + var rootServiceProvider = context.ServiceProvider.GetRequiredService(); + + 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)) + { + 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 new file mode 100644 index 0000000000..f2e73cefc0 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +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.Threading; + +namespace Volo.Abp.PermissionManagement; + +[Dependency(ReplaceServices = true)] +public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ITransientDependency +{ + protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; } + protected IPermissionDefinitionRecordRepository PermissionRepository { get; } + protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; } + protected IDynamicPermissionDefinitionStoreInMemoryCache StoreCache { get; } + protected IDistributedCache DistributedCache { get; } + protected IAbpDistributedLock DistributedLock { get; } + public PermissionManagementOptions PermissionManagementOptions { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + + public DynamicPermissionDefinitionStore( + IPermissionGroupDefinitionRecordRepository permissionGroupRepository, + IPermissionDefinitionRecordRepository permissionRepository, + IPermissionDefinitionSerializer permissionDefinitionSerializer, + IDynamicPermissionDefinitionStoreInMemoryCache storeCache, + IDistributedCache distributedCache, + IOptions cacheOptions, + IOptions permissionManagementOptions, + IAbpDistributedLock distributedLock) + { + PermissionGroupRepository = permissionGroupRepository; + PermissionRepository = permissionRepository; + PermissionDefinitionSerializer = permissionDefinitionSerializer; + StoreCache = storeCache; + DistributedCache = distributedCache; + DistributedLock = distributedLock; + PermissionManagementOptions = permissionManagementOptions.Value; + CacheOptions = cacheOptions.Value; + } + + public virtual async Task GetOrNullAsync(string name) + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return null; + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissionOrNull(name); + } + } + + public virtual async Task> GetPermissionsAsync() + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return Array.Empty(); + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetPermissions().ToImmutableList(); + } + } + + public virtual async Task> GetGroupsAsync() + { + if (!PermissionManagementOptions.IsDynamicPermissionStoreEnabled) + { + return Array.Empty(); + } + + using (await StoreCache.SyncSemaphore.LockAsync()) + { + await EnsureCacheIsUptoDateAsync(); + return StoreCache.GetGroups().ToImmutableList(); + } + } + + 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; + } + + protected virtual async Task UpdateInMemoryStoreCache() + { + var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); + var permissionRecords = await PermissionRepository.GetListAsync(); + + await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); + } + + protected virtual 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; + } + + protected virtual string GetCommonStampCacheKey() + { + return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; + } + + protected virtual string GetCommonDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..3b09c922dc --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs @@ -0,0 +1,127 @@ +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; +using Volo.Abp.Localization; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.PermissionManagement; + +public class DynamicPermissionDefinitionStoreInMemoryCache : + IDynamicPermissionDefinitionStoreInMemoryCache, + ISingletonDependency +{ + public string CacheStamp { get; set; } + + 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, + ILocalizableStringSerializer localizableStringSerializer) + { + StateCheckerSerializer = stateCheckerSerializer; + LocalizableStringSerializer = localizableStringSerializer; + + PermissionGroupDefinitions = new Dictionary(); + PermissionDefinitions = new Dictionary(); + } + + public Task FillAsync( + List permissionGroupRecords, + List permissionRecords) + { + PermissionGroupDefinitions.Clear(); + PermissionDefinitions.Clear(); + + var context = new PermissionDefinitionContext(null); + + foreach (var permissionGroupRecord in permissionGroupRecords) + { + var permissionGroup = context.AddGroup( + permissionGroupRecord.Name, + LocalizableStringSerializer.Deserialize(permissionGroupRecord.DisplayName) + ); + + PermissionGroupDefinitions[permissionGroup.Name] = permissionGroup; + + 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.Where(x => x.ParentName == null)) + { + 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) + { + var permission = permissionContainer.AddPermission( + permissionRecord.Name, + LocalizableStringSerializer.Deserialize(permissionRecord.DisplayName), + permissionRecord.MultiTenancySide, + permissionRecord.IsEnabled + ); + + PermissionDefinitions[permission.Name] = permission; + + if (!permissionRecord.Providers.IsNullOrWhiteSpace()) + { + permission.Providers.AddRange(permissionRecord.Providers.Split(',')); + } + + if (!permissionRecord.StateCheckers.IsNullOrWhiteSpace()) + { + var checkers = StateCheckerSerializer + .DeserializeArray( + permissionRecord.StateCheckers, + permission + ); + 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); + } + } +} \ 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..2dab588ebd --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs @@ -0,0 +1,26 @@ +using System; +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; } + + DateTime? LastCheckTime { get; set; } + + 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/IPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..e332d8483d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionRecordRepository.cs @@ -0,0 +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.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..8ed09a4380 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionDefinitionSerializer.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.PermissionManagement; + +public interface IPermissionDefinitionSerializer +{ + Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> + SerializeAsync(IEnumerable permissionGroups); + + Task SerializeAsync( + PermissionGroupDefinition permissionGroup); + + 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/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.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/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/PermissionDefinitionRecord.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs new file mode 100644 index 0000000000..2ba9ffa26a --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionRecord.cs @@ -0,0 +1,175 @@ +using System; +using System.Text.Json.Serialization; +using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +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; } + + public string ParentName { get; set; } + + public string DisplayName { get; set; } + + public bool IsEnabled { get; set; } + + public MultiTenancySides MultiTenancySide { get; set; } + + /// + /// Comma separated list of provider names. + /// + public string Providers { get; set; } + + /// + /// Serialized string to store info about the state checkers. + /// + public string StateCheckers { get; set; } + + public ExtraPropertyDictionary ExtraProperties { get; protected set; } + + public PermissionDefinitionRecord() + { + 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.Length(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(); + } + + 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/PermissionDefinitionSerializer.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs new file mode 100644 index 0000000000..8e63342502 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +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 ISimpleStateCheckerSerializer StateCheckerSerializer { get; } + protected IGuidGenerator GuidGenerator { get; } + protected ILocalizableStringSerializer LocalizableStringSerializer { get; } + + public PermissionDefinitionSerializer( + IGuidGenerator guidGenerator, + ISimpleStateCheckerSerializer stateCheckerSerializer, + ILocalizableStringSerializer localizableStringSerializer) + { + StateCheckerSerializer = stateCheckerSerializer; + LocalizableStringSerializer = localizableStringSerializer; + GuidGenerator = guidGenerator; + } + + public async Task<(PermissionGroupDefinitionRecord[], PermissionDefinitionRecord[])> + 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.ToArray(), permissionRecords.ToArray()); + } + + public Task SerializeAsync(PermissionGroupDefinition permissionGroup) + { + using (CultureHelper.Use(CultureInfo.InvariantCulture)) + { + var permissionGroupRecord = new PermissionGroupDefinitionRecord( + GuidGenerator.Create(), + permissionGroup.Name, + LocalizableStringSerializer.Serialize(permissionGroup.DisplayName) + ); + + foreach (var property in permissionGroup.Properties) + { + permissionGroupRecord.SetProperty(property.Key, property.Value); + } + + return Task.FromResult(permissionGroupRecord); + } + } + + 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, + LocalizableStringSerializer.Serialize(permission.DisplayName), + 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); + } + } + + 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 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..f93bf57e21 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGroupDefinitionRecord.cs @@ -0,0 +1,84 @@ +using System; +using System.Text.Json.Serialization; +using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; + +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; } + + public ExtraPropertyDictionary ExtraProperties { get; protected set; } + + public PermissionGroupDefinitionRecord() + { + 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(); + } + + 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 otherRecord) + { + if (Name != otherRecord.Name) + { + Name = otherRecord.Name; + } + + if (DisplayName != otherRecord.DisplayName) + { + DisplayName = otherRecord.DisplayName; + } + + 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/PermissionManagementOptions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs index 15da755a33..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 @@ -8,10 +8,27 @@ public class PermissionManagementOptions public ITypeList ManagementProviders { get; } 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() { 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/PermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManager.cs index 2e709c49c2..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,18 +62,62 @@ public class PermissionManager : IPermissionManager, ISingletonDependency public virtual async Task GetAsync(string permissionName, string providerName, string providerKey) { - return await GetInternalAsync(PermissionDefinitionManager.Get(permissionName), providerName, providerKey); + var permission = await PermissionDefinitionManager.GetOrNullAsync(permissionName); + if (permission == null) + { + return new PermissionWithGrantedProviders(permissionName, false); + } + + return await GetInternalAsync( + 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 = permissionNames.Select(x => PermissionDefinitionManager.Get(x)).ToArray(); - return await GetInternalAsync(permissionDefinitions, providerName, providerKey); + 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); + } + } + + if (!permissions.Any()) + { + return new MultiplePermissionWithGrantedProviders(undefinedPermissions.ToArray()); + } + + 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) { - var permissionDefinitions = PermissionDefinitionManager.GetPermissions().ToArray(); + var permissionDefinitions = (await PermissionDefinitionManager.GetPermissionsAsync()).ToArray(); var multiplePermissionWithGrantedProviders = await GetInternalAsync(permissionDefinitions, providerName, providerKey); @@ -83,7 +127,13 @@ 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.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)) { @@ -146,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/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}"); 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..5754031509 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs @@ -0,0 +1,294 @@ +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.Threading; +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; } + protected IDistributedCache Cache { get; } + protected IApplicationNameAccessor ApplicationNameAccessor { get; } + protected IAbpDistributedLock DistributedLock { get; } + protected PermissionManagementOptions PermissionManagementOptions { get; } + protected ICancellationTokenProvider CancellationTokenProvider { get; } + protected AbpDistributedCacheOptions CacheOptions { get; } + + public StaticPermissionSaver( + IStaticPermissionDefinitionStore staticStore, + IPermissionGroupDefinitionRecordRepository permissionGroupRepository, + IPermissionDefinitionRecordRepository permissionRepository, + IPermissionDefinitionSerializer permissionSerializer, + IDistributedCache cache, + IOptions cacheOptions, + IApplicationNameAccessor applicationNameAccessor, + IAbpDistributedLock distributedLock, + IOptions permissionManagementOptions, + ICancellationTokenProvider cancellationTokenProvider) + { + StaticStore = staticStore; + PermissionGroupRepository = permissionGroupRepository; + PermissionRepository = permissionRepository; + PermissionSerializer = permissionSerializer; + Cache = cache; + ApplicationNameAccessor = applicationNameAccessor; + DistributedLock = distributedLock; + CancellationTokenProvider = cancellationTokenProvider; + PermissionManagementOptions = permissionManagementOptions.Value; + CacheOptions = cacheOptions.Value; + } + + [UnitOfWork] + public virtual async Task SaveAsync() + { + await using var applicationLockHandle = await DistributedLock.TryAcquireAsync( + GetApplicationDistributedLockKey() + ); + + if (applicationLockHandle == null) + { + /* Another application instance is already doing 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. This is enough for now. + */ + + var cacheKey = GetApplicationHashCacheKey(); + var cachedHash = await Cache.GetStringAsync(cacheKey, CancellationTokenProvider.Token); + + var (permissionGroupRecords, permissionRecords) = await PermissionSerializer.SerializeAsync( + await StaticStore.GetGroupsAsync() + ); + + var currentHash = CalculateHash( + permissionGroupRecords, + permissionRecords, + PermissionManagementOptions.DeletedPermissionGroups, + PermissionManagementOptions.DeletedPermissions + ); + + if (cachedHash == currentHash) + { + return; + } + + 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? + }, + CancellationTokenProvider.Token + ); + } + } + + await Cache.SetStringAsync( + cacheKey, + currentHash, + new DistributedCacheEntryOptions { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + }, + CancellationTokenProvider.Token + ); + } + + private async Task UpdateChangedPermissionGroupsAsync( + IEnumerable 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 = PermissionManagementOptions.DeletedPermissionGroups.Any() + ? permissionGroupRecordsInDatabase.Values + .Where(x => PermissionManagementOptions.DeletedPermissionGroups.Contains(x.Name)) + .ToArray() + : Array.Empty(); + + if (newRecords.Any()) + { + await PermissionGroupRepository.InsertManyAsync(newRecords); + } + + if (changedRecords.Any()) + { + await PermissionGroupRepository.UpdateManyAsync(changedRecords); + } + + if (deletedRecords.Any()) + { + await PermissionGroupRepository.DeleteManyAsync(deletedRecords); + } + + return newRecords.Any() || changedRecords.Any() || deletedRecords.Any(); + } + + 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 = 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()) + { + await PermissionRepository.InsertManyAsync(newRecords); + } + + if (changedRecords.Any()) + { + await PermissionRepository.UpdateManyAsync(changedRecords); + } + + if (deletedRecords.Any()) + { + await PermissionRepository.DeleteManyAsync(deletedRecords); + } + + return newRecords.Any() || changedRecords.Any() || deletedRecords.Any(); + } + + private string GetApplicationDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionUpdateLock"; + } + + private string GetCommonDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; + } + + private string GetApplicationHashCacheKey() + { + return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionsHash"; + } + + private string GetCommonStampCacheKey() + { + return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; + } + + 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/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..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 @@ -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); + b.Property(x => x.StateCheckers).HasMaxLength(PermissionDefinitionRecordConsts.MaxStateCheckersLength); + + 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/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..09cf408f7d --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionDefinitionRecordRepository.cs @@ -0,0 +1,29 @@ +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; + +namespace Volo.Abp.PermissionManagement.EntityFrameworkCore; + +public class EfCorePermissionDefinitionRecordRepository : + EfCoreRepository, + IPermissionDefinitionRecordRepository +{ + public EfCorePermissionDefinitionRecordRepository( + IDbContextProvider dbContextProvider) + : 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.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.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/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/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/MongoPermissionDefinitionRecordRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs new file mode 100644 index 0000000000..e4894a1442 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionDefinitionRecordRepository.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using MongoDB.Driver.Linq; +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) + { + } + + 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 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) 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 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) 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(); 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/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/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..1e7c04580c --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionDefinitionSerializer_Tests.cs @@ -0,0 +1,93 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +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 Volo.Abp.PermissionManagement.Localization; +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_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("F:Group one"); + permissionGroupRecord.GetProperty("CustomProperty1").ShouldBe("CustomValue1"); + } + + [Fact] + public async Task Serialize_Complex_Permission_Definition() + { + // Arrange + + var context = new PermissionDefinitionContext(null); + var group1 = CreatePermissionGroup1(context); + var permission1 = group1.AddPermission( + "Permission1", + new LocalizableString(typeof(AbpPermissionManagementResource), "Permission1"), + MultiTenancySides.Tenant + ) + .WithProviders("ProviderA", "ProviderB") + .WithProperty("CustomProperty2", "CustomValue2") + .RequireAuthenticated() //For for testing, not so meaningful + .RequireGlobalFeatures("GlobalFeature1", "GlobalFeature2") + .RequireFeatures("Feature1", "Feature2") + .RequirePermissions(requiresAll: false, batchCheck: false,"Permission2", "Permission3"); + + // Act + + var permissionRecord = await _serializer.SerializeAsync( + permission1, + group1 + ); + + //Assert + + permissionRecord.Name.ShouldBe("Permission1"); + permissionRecord.GroupName.ShouldBe("Group1"); + permissionRecord.DisplayName.ShouldBe("L:AbpPermissionManagement,Permission1"); + 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\"]},{\"T\":\"P\",\"A\":false,\"N\":[\"Permission2\",\"Permission3\"]}]"); + } + + 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 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] 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")