diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeFeatureDefinitionManager.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeFeatureDefinitionManager.cs new file mode 100644 index 000000000..1bcefc35c --- /dev/null +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeFeatureDefinitionManager.cs @@ -0,0 +1,220 @@ +using System.Collections.Immutable; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Features; + +namespace LINGYUN.Abp.MicroService.AdminService.Overrides; + +[Dependency(ReplaceServices = true)] +public class MergeFeatureDefinitionManager : FeatureDefinitionManager +{ + public MergeFeatureDefinitionManager( + IStaticFeatureDefinitionStore staticStore, + IDynamicFeatureDefinitionStore dynamicStore) + : base(staticStore, dynamicStore) + { + } + + public async override Task> GetAllAsync() + { + var staticFeatures = await StaticStore.GetFeaturesAsync(); + var dynamicFeatures = await DynamicStore.GetFeaturesAsync(); + + var mergedFeatures = new Dictionary(); + + foreach (var staticFeature in staticFeatures) + { + mergedFeatures[staticFeature.Name] = staticFeature; + } + + foreach (var dynamicFeature in dynamicFeatures) + { + if (mergedFeatures.TryGetValue(dynamicFeature.Name, out var existingFeature)) + { + MergeFeatureMetadata(existingFeature, dynamicFeature); + + foreach (var child in dynamicFeature.Children) + { + MergeChildFeature(existingFeature, child); + } + } + else + { + mergedFeatures[dynamicFeature.Name] = dynamicFeature; + } + } + + return mergedFeatures.Values.ToImmutableList(); + } + + public async override Task> GetGroupsAsync() + { + var staticGroups = await StaticStore.GetGroupsAsync(); + var dynamicGroups = await DynamicStore.GetGroupsAsync(); + + var mergedGroups = new Dictionary(); + + foreach (var staticGroup in staticGroups) + { + mergedGroups[staticGroup.Name] = staticGroup; + } + + foreach (var dynamicGroup in dynamicGroups) + { + if (mergedGroups.TryGetValue(dynamicGroup.Name, out var existingGroup)) + { + MergeGroupFeatures(existingGroup, dynamicGroup); + } + else + { + mergedGroups[dynamicGroup.Name] = dynamicGroup; + } + } + + return mergedGroups.Values.ToImmutableList(); + } + + private static void MergeGroupFeatures(FeatureGroupDefinition target, FeatureGroupDefinition source) + { + foreach (var sourceFeature in source.Features) + { + var existingFeature = target.GetFeatureOrNull(sourceFeature.Name); + + if (existingFeature == null) + { + var newFeature = target.AddFeature( + sourceFeature.Name, + sourceFeature.DefaultValue, + sourceFeature.DisplayName, + sourceFeature.Description, + sourceFeature.ValueType, + sourceFeature.IsVisibleToClients, + sourceFeature.IsAvailableToHost + ); + + CopyFeatureDetails(sourceFeature, newFeature); + + foreach (var child in sourceFeature.Children) + { + AddChildFeatureRecursively(newFeature, child); + } + } + else + { + MergeFeatureMetadata(existingFeature, sourceFeature); + + foreach (var child in sourceFeature.Children) + { + MergeChildFeature(existingFeature, child); + } + } + } + } + + private static void AddChildFeatureRecursively(FeatureDefinition parent, FeatureDefinition sourceChild) + { + var newChild = parent.CreateChild( + sourceChild.Name, + sourceChild.DefaultValue, + sourceChild.DisplayName, + sourceChild.Description, + sourceChild.ValueType, + sourceChild.IsVisibleToClients, + sourceChild.IsAvailableToHost + ); + + CopyFeatureDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildFeatureRecursively(newChild, grandchild); + } + } + + private static void MergeChildFeature(FeatureDefinition parent, FeatureDefinition sourceChild) + { + var existingChild = parent.Children.FirstOrDefault(c => c.Name == sourceChild.Name); + + if (existingChild == null) + { + var newChild = parent.CreateChild( + sourceChild.Name, + sourceChild.DefaultValue, + sourceChild.DisplayName, + sourceChild.Description, + sourceChild.ValueType, + sourceChild.IsVisibleToClients, + sourceChild.IsAvailableToHost + ); + CopyFeatureDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildFeatureRecursively(newChild, grandchild); + } + } + else + { + MergeFeatureMetadata(existingChild, sourceChild); + + foreach (var grandchild in sourceChild.Children) + { + MergeChildFeature(existingChild, grandchild); + } + } + } + + private static void CopyFeatureDetails(FeatureDefinition source, FeatureDefinition target) + { + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.AllowedProviders) + { + if (!target.AllowedProviders.Contains(provider)) + { + target.AllowedProviders.Add(provider); + } + } + } + + private static void MergeFeatureMetadata(FeatureDefinition target, FeatureDefinition source) + { + if (source.DisplayName != null) + { + target.DisplayName = source.DisplayName; + } + + if (source.Description != null) + { + target.Description = source.Description; + } + + if (source.DefaultValue != null) + { + target.DefaultValue = source.DefaultValue; + } + + if (source.ValueType != null) + { + target.ValueType = source.ValueType; + } + + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.AllowedProviders) + { + if (!target.AllowedProviders.Contains(provider)) + { + target.AllowedProviders.Add(provider); + } + } + + target.IsVisibleToClients = target.IsVisibleToClients || source.IsVisibleToClients; + target.IsAvailableToHost = target.IsAvailableToHost || source.IsAvailableToHost; + } +} diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergePermissionDefinitionManager.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergePermissionDefinitionManager.cs new file mode 100644 index 000000000..5d3f92222 --- /dev/null +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergePermissionDefinitionManager.cs @@ -0,0 +1,186 @@ +using System.Collections.Immutable; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace LINGYUN.Abp.MicroService.AdminService.Overrides; + +[Dependency(ReplaceServices = true)] +public class MergePermissionDefinitionManager : PermissionDefinitionManager +{ + private readonly IStaticPermissionDefinitionStore _staticStore; + private readonly IDynamicPermissionDefinitionStore _dynamicStore; + + public MergePermissionDefinitionManager( + IStaticPermissionDefinitionStore staticStore, + IDynamicPermissionDefinitionStore dynamicStore) : base(staticStore, dynamicStore) + { + _staticStore = staticStore; + _dynamicStore = dynamicStore; + } + + public async override Task> GetGroupsAsync() + { + var staticGroups = await _staticStore.GetGroupsAsync(); + var dynamicGroups = await _dynamicStore.GetGroupsAsync(); + + var mergedGroups = new Dictionary(); + + foreach (var staticGroup in staticGroups) + { + mergedGroups[staticGroup.Name] = staticGroup; + } + + foreach (var dynamicGroup in dynamicGroups) + { + if (mergedGroups.TryGetValue(dynamicGroup.Name, out var existingGroup)) + { + MergeGroupPermissions(existingGroup, dynamicGroup); + } + else + { + mergedGroups[dynamicGroup.Name] = dynamicGroup; + } + } + + return mergedGroups.Values.ToImmutableList(); + } + + private static void MergeGroupPermissions(PermissionGroupDefinition target, PermissionGroupDefinition source) + { + foreach (var sourcePermission in source.Permissions) + { + var existingPermission = target.GetPermissionOrNull(sourcePermission.Name); + + if (existingPermission == null) + { + var newPermission = target.AddPermission( + sourcePermission.Name, + sourcePermission.DisplayName, + sourcePermission.MultiTenancySide, + sourcePermission.IsEnabled + ); + + CopyPermissionDetails(sourcePermission, newPermission); + + foreach (var child in sourcePermission.Children) + { + AddChildPermissionRecursively(newPermission, child); + } + } + else + { + MergePermissionMetadata(existingPermission, sourcePermission); + + foreach (var sourceChild in sourcePermission.Children) + { + MergeChildPermissions(existingPermission, sourceChild); + } + } + } + } + + private static void AddChildPermissionRecursively(PermissionDefinition parent, PermissionDefinition sourceChild) + { + var newChild = parent.AddChild( + sourceChild.Name, + sourceChild.DisplayName, + sourceChild.MultiTenancySide, + sourceChild.IsEnabled + ); + + CopyPermissionDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildPermissionRecursively(newChild, grandchild); + } + } + + private static void MergeChildPermissions(PermissionDefinition parent, PermissionDefinition sourceChild) + { + var existingChild = parent.Children.FirstOrDefault(c => c.Name == sourceChild.Name); + + if (existingChild == null) + { + var newChild = parent.AddChild( + sourceChild.Name, + sourceChild.DisplayName, + sourceChild.MultiTenancySide, + sourceChild.IsEnabled + ); + CopyPermissionDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildPermissionRecursively(newChild, grandchild); + } + } + else + { + MergePermissionMetadata(existingChild, sourceChild); + + foreach (var grandchild in sourceChild.Children) + { + MergeChildPermissions(existingChild, grandchild); + } + } + } + + private static void CopyPermissionDetails(PermissionDefinition source, PermissionDefinition target) + { + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.Providers) + { + if (!target.Providers.Contains(provider)) + { + target.Providers.Add(provider); + } + } + + foreach (var checker in source.StateCheckers) + { + if (!target.StateCheckers.Contains(checker)) + { + target.StateCheckers.Add(checker); + } + } + } + + private static void MergePermissionMetadata(PermissionDefinition target, PermissionDefinition source) + { + target.DisplayName = source.DisplayName; + + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.Providers) + { + if (!target.Providers.Contains(provider)) + { + target.Providers.Add(provider); + } + } + + foreach (var checker in source.StateCheckers) + { + if (!target.StateCheckers.Contains(checker)) + { + target.StateCheckers.Add(checker); + } + } + + if (source.MultiTenancySide != MultiTenancySides.Both) + { + target.MultiTenancySide |= source.MultiTenancySide; + } + + target.IsEnabled = target.IsEnabled || source.IsEnabled; + } +} \ No newline at end of file diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeSettingDefinitionManager.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeSettingDefinitionManager.cs new file mode 100644 index 000000000..7eb4ee257 --- /dev/null +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeSettingDefinitionManager.cs @@ -0,0 +1,72 @@ +using System.Collections.Immutable; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Settings; + +namespace LINGYUN.Abp.MicroService.AdminService.Overrides; + +[Dependency(ReplaceServices = true)] +public class MergeSettingDefinitionManager : SettingDefinitionManager +{ + private readonly IStaticSettingDefinitionStore _staticStore; + private readonly IDynamicSettingDefinitionStore _dynamicStore; + + public MergeSettingDefinitionManager( + IStaticSettingDefinitionStore staticStore, + IDynamicSettingDefinitionStore dynamicStore) + : base(staticStore, dynamicStore) + { + _staticStore = staticStore; + _dynamicStore = dynamicStore; + } + + public async override Task> GetAllAsync() + { + var staticSettings = await _staticStore.GetAllAsync(); + var dynamicSettings = await _dynamicStore.GetAllAsync(); + + var mergedSettings = new Dictionary(); + + foreach (var staticSetting in staticSettings) + { + mergedSettings[staticSetting.Name] = staticSetting; + } + + foreach (var dynamicSetting in dynamicSettings) + { + if (mergedSettings.TryGetValue(dynamicSetting.Name, out var existingSetting)) + { + MergeSetting(existingSetting, dynamicSetting); + } + else + { + mergedSettings[dynamicSetting.Name] = dynamicSetting; + } + } + + return mergedSettings.Values.ToImmutableList(); + } + + private static void MergeSetting(SettingDefinition target, SettingDefinition source) + { + target.DisplayName = source.DisplayName; + target.Description = source.Description ?? target.Description; + target.DefaultValue = source.DefaultValue ?? target.DefaultValue; + target.IsVisibleToClients = target.IsVisibleToClients || source.IsVisibleToClients; + target.IsInherited = target.IsInherited || source.IsInherited; + target.IsEncrypted = target.IsEncrypted || source.IsEncrypted; + + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.Providers) + { + if (!target.Providers.Contains(provider)) + { + target.Providers.Add(provider); + } + } + } +} + diff --git a/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeTemplateDefinitionManager.cs b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeTemplateDefinitionManager.cs new file mode 100644 index 000000000..9fe58573a --- /dev/null +++ b/aspnet-core/aspire/LINGYUN.Abp.MicroService.AdminService/Overrides/MergeTemplateDefinitionManager.cs @@ -0,0 +1,84 @@ +using System.Collections.Immutable; +using Volo.Abp.DependencyInjection; +using Volo.Abp.TextTemplating; + +namespace LINGYUN.Abp.MicroService.AdminService.Overrides; + + +[Dependency(ReplaceServices = true)] +public class MergeTemplateDefinitionManager : TemplateDefinitionManager +{ + public MergeTemplateDefinitionManager( + IStaticTemplateDefinitionStore staticStore, + IDynamicTemplateDefinitionStore dynamicStore) + : base(staticStore, dynamicStore) + { + } + public async override Task> GetAllAsync() + { + var staticTemplates = await StaticStore.GetAllAsync(); + var dynamicTemplates = await DynamicStore.GetAllAsync(); + + var mergedTemplates = new Dictionary(); + + foreach (var staticTemplate in staticTemplates) + { + mergedTemplates[staticTemplate.Name] = staticTemplate; + } + + foreach (var dynamicTemplate in dynamicTemplates) + { + if (mergedTemplates.TryGetValue(dynamicTemplate.Name, out var existingTemplate)) + { + MergeTemplate(existingTemplate, dynamicTemplate); + } + else + { + mergedTemplates[dynamicTemplate.Name] = dynamicTemplate; + } + } + + return mergedTemplates.Values.ToImmutableList(); + } + + private static TemplateDefinition MergeTemplate(TemplateDefinition staticTemplate, TemplateDefinition dynamicTemplate) + { + var localizationResourceName = dynamicTemplate.LocalizationResourceName ?? staticTemplate.LocalizationResourceName; + var defaultCultureName = dynamicTemplate.DefaultCultureName ?? staticTemplate.DefaultCultureName; + var displayName = dynamicTemplate.DisplayName ?? staticTemplate.DisplayName; + var isLayout = dynamicTemplate.IsLayout || staticTemplate.IsLayout; + var layout = dynamicTemplate.Layout ?? staticTemplate.Layout; + + var mergedTemplate = new TemplateDefinition( + staticTemplate.Name, + localizationResourceName, + displayName, + isLayout, + layout, + defaultCultureName + ); + + foreach (var property in staticTemplate.Properties) + { + mergedTemplate.Properties[property.Key] = property.Value; + } + + foreach (var property in dynamicTemplate.Properties) + { + mergedTemplate.Properties[property.Key] = property.Value; + } + + if (!string.IsNullOrEmpty(dynamicTemplate.RenderEngine)) + { + mergedTemplate.RenderEngine = dynamicTemplate.RenderEngine; + } + else if (!string.IsNullOrEmpty(staticTemplate.RenderEngine)) + { + mergedTemplate.RenderEngine = staticTemplate.RenderEngine; + } + + mergedTemplate.IsInlineLocalized = dynamicTemplate.IsInlineLocalized || staticTemplate.IsInlineLocalized; + + return mergedTemplate; + } +} diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs deleted file mode 100644 index 5dfe92789..000000000 --- a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.RequestLocalization; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; -using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending; -using Volo.Abp.Authorization; -using Volo.Abp.Authorization.Permissions; -using Volo.Abp.Data; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Features; -using Volo.Abp.Localization; -using Volo.Abp.MultiTenancy; -using Volo.Abp.Settings; -using Volo.Abp.Timing; -using Volo.Abp.Users; - -namespace LY.MicroService.BackendAdmin.ApplicationConfigurations; - -[Dependency(ReplaceServices = true)] -public class AbpApplicationConfigurationAppService : Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationAppService -{ - private readonly IServiceProvider _serviceProvider; - private readonly AbpApplicationConfigurationOptions _options; - private readonly ICachedObjectExtensionsDtoService _cachedObjectExtensionsDtoService; - - private readonly ISettingProvider _settingProvider; - private readonly ISettingDefinitionManager _settingDefinitionManager; - - public AbpApplicationConfigurationAppService( - IOptions localizationOptions, - IOptions requestLocalizationOptions, - IOptions multiTenancyOptions, - IServiceProvider serviceProvider, - IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider, - IPermissionDefinitionManager permissionDefinitionManager, - DefaultAuthorizationPolicyProvider defaultAuthorizationPolicyProvider, - IPermissionChecker permissionChecker, - IAuthorizationService authorizationService, - ICurrentUser currentUser, - ISettingProvider settingProvider, - ISettingDefinitionManager settingDefinitionManager, - IFeatureDefinitionManager featureDefinitionManager, - ILanguageProvider languageProvider, - ITimezoneProvider timezoneProvider, - IOptions abpClockOptions, - ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService, - IOptions options) - : base( - localizationOptions, - requestLocalizationOptions, - multiTenancyOptions, - serviceProvider, - abpAuthorizationPolicyProvider, - permissionDefinitionManager, - defaultAuthorizationPolicyProvider, - permissionChecker, - authorizationService, - currentUser, - settingProvider, - settingDefinitionManager, - featureDefinitionManager, - languageProvider, - timezoneProvider, - abpClockOptions, - cachedObjectExtensionsDtoService, - options) - { - _options = options.Value; - _serviceProvider = serviceProvider; - _cachedObjectExtensionsDtoService = cachedObjectExtensionsDtoService; - - _settingProvider = settingProvider; - _settingDefinitionManager = settingDefinitionManager; - } - - public override async Task GetAsync(ApplicationConfigurationRequestOptions options) - { - //TODO: Optimize & cache..? - - Logger.LogDebug("Executing AbpApplicationConfigurationAppService.GetAsync()..."); - - var result = new ApplicationConfigurationDto - { - Auth = await GetAuthConfigAsync(), - Features = await GetFeaturesConfigAsync(), - GlobalFeatures = await GetGlobalFeaturesConfigAsync(), - Localization = await GetLocalizationConfigAsync(options), - CurrentUser = GetCurrentUser(), - Setting = await GetSettingConfigAsync(), - MultiTenancy = GetMultiTenancy(), - CurrentTenant = GetCurrentTenant(), - Timing = await GetTimingConfigAsync(), - Clock = GetClockConfig(), - ObjectExtensions = _cachedObjectExtensionsDtoService.Get(), - ExtraProperties = new ExtraPropertyDictionary() - }; - - if (_options.Contributors.Any()) - { - using (var scope = _serviceProvider.CreateScope()) - { - var context = new ApplicationConfigurationContributorContext(scope.ServiceProvider, result); - foreach (var contributor in _options.Contributors) - { - await contributor.ContributeAsync(context); - } - } - } - - Logger.LogDebug("Executed AbpApplicationConfigurationAppService.GetAsync()."); - - return result; - } - - protected async virtual Task GetSettingConfigAsync() - { - var result = new ApplicationSettingConfigurationDto - { - Values = new Dictionary() - }; - - var settingDefinitions = (await _settingDefinitionManager.GetAllAsync()).Where(x => x.IsVisibleToClients); - var settingNames = settingDefinitions.Select(x => x.Name).ToArray(); - if (settingNames.Length > 0) - { - var settingValues = await _settingProvider.GetAllAsync(settingNames); - - foreach (var settingValue in settingValues) - { - result.Values[settingValue.Name] = settingValue.Value; - } - } - - return result; - } -} diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeFeatureDefinitionManager.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeFeatureDefinitionManager.cs new file mode 100644 index 000000000..645d6e1bf --- /dev/null +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeFeatureDefinitionManager.cs @@ -0,0 +1,223 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Features; + +namespace LY.MicroService.BackendAdmin.Overrides; + +[Dependency(ReplaceServices = true)] +public class MergeFeatureDefinitionManager : FeatureDefinitionManager +{ + public MergeFeatureDefinitionManager( + IStaticFeatureDefinitionStore staticStore, + IDynamicFeatureDefinitionStore dynamicStore) + : base(staticStore, dynamicStore) + { + } + + public async override Task> GetAllAsync() + { + var staticFeatures = await StaticStore.GetFeaturesAsync(); + var dynamicFeatures = await DynamicStore.GetFeaturesAsync(); + + var mergedFeatures = new Dictionary(); + + foreach (var staticFeature in staticFeatures) + { + mergedFeatures[staticFeature.Name] = staticFeature; + } + + foreach (var dynamicFeature in dynamicFeatures) + { + if (mergedFeatures.TryGetValue(dynamicFeature.Name, out var existingFeature)) + { + MergeFeatureMetadata(existingFeature, dynamicFeature); + + foreach (var child in dynamicFeature.Children) + { + MergeChildFeature(existingFeature, child); + } + } + else + { + mergedFeatures[dynamicFeature.Name] = dynamicFeature; + } + } + + return mergedFeatures.Values.ToImmutableList(); + } + + public async override Task> GetGroupsAsync() + { + var staticGroups = await StaticStore.GetGroupsAsync(); + var dynamicGroups = await DynamicStore.GetGroupsAsync(); + + var mergedGroups = new Dictionary(); + + foreach (var staticGroup in staticGroups) + { + mergedGroups[staticGroup.Name] = staticGroup; + } + + foreach (var dynamicGroup in dynamicGroups) + { + if (mergedGroups.TryGetValue(dynamicGroup.Name, out var existingGroup)) + { + MergeGroupFeatures(existingGroup, dynamicGroup); + } + else + { + mergedGroups[dynamicGroup.Name] = dynamicGroup; + } + } + + return mergedGroups.Values.ToImmutableList(); + } + + private static void MergeGroupFeatures(FeatureGroupDefinition target, FeatureGroupDefinition source) + { + foreach (var sourceFeature in source.Features) + { + var existingFeature = target.GetFeatureOrNull(sourceFeature.Name); + + if (existingFeature == null) + { + var newFeature = target.AddFeature( + sourceFeature.Name, + sourceFeature.DefaultValue, + sourceFeature.DisplayName, + sourceFeature.Description, + sourceFeature.ValueType, + sourceFeature.IsVisibleToClients, + sourceFeature.IsAvailableToHost + ); + + CopyFeatureDetails(sourceFeature, newFeature); + + foreach (var child in sourceFeature.Children) + { + AddChildFeatureRecursively(newFeature, child); + } + } + else + { + MergeFeatureMetadata(existingFeature, sourceFeature); + + foreach (var child in sourceFeature.Children) + { + MergeChildFeature(existingFeature, child); + } + } + } + } + + private static void AddChildFeatureRecursively(FeatureDefinition parent, FeatureDefinition sourceChild) + { + var newChild = parent.CreateChild( + sourceChild.Name, + sourceChild.DefaultValue, + sourceChild.DisplayName, + sourceChild.Description, + sourceChild.ValueType, + sourceChild.IsVisibleToClients, + sourceChild.IsAvailableToHost + ); + + CopyFeatureDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildFeatureRecursively(newChild, grandchild); + } + } + + private static void MergeChildFeature(FeatureDefinition parent, FeatureDefinition sourceChild) + { + var existingChild = parent.Children.FirstOrDefault(c => c.Name == sourceChild.Name); + + if (existingChild == null) + { + var newChild = parent.CreateChild( + sourceChild.Name, + sourceChild.DefaultValue, + sourceChild.DisplayName, + sourceChild.Description, + sourceChild.ValueType, + sourceChild.IsVisibleToClients, + sourceChild.IsAvailableToHost + ); + CopyFeatureDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildFeatureRecursively(newChild, grandchild); + } + } + else + { + MergeFeatureMetadata(existingChild, sourceChild); + + foreach (var grandchild in sourceChild.Children) + { + MergeChildFeature(existingChild, grandchild); + } + } + } + + private static void CopyFeatureDetails(FeatureDefinition source, FeatureDefinition target) + { + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.AllowedProviders) + { + if (!target.AllowedProviders.Contains(provider)) + { + target.AllowedProviders.Add(provider); + } + } + } + + private static void MergeFeatureMetadata(FeatureDefinition target, FeatureDefinition source) + { + if (source.DisplayName != null) + { + target.DisplayName = source.DisplayName; + } + + if (source.Description != null) + { + target.Description = source.Description; + } + + if (source.DefaultValue != null) + { + target.DefaultValue = source.DefaultValue; + } + + if (source.ValueType != null) + { + target.ValueType = source.ValueType; + } + + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.AllowedProviders) + { + if (!target.AllowedProviders.Contains(provider)) + { + target.AllowedProviders.Add(provider); + } + } + + target.IsVisibleToClients = target.IsVisibleToClients || source.IsVisibleToClients; + target.IsAvailableToHost = target.IsAvailableToHost || source.IsAvailableToHost; + } +} diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergePermissionDefinitionManager.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergePermissionDefinitionManager.cs new file mode 100644 index 000000000..889516ee2 --- /dev/null +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergePermissionDefinitionManager.cs @@ -0,0 +1,189 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace LY.MicroService.BackendAdmin.Overrides; + +[Dependency(ReplaceServices = true)] +public class MergePermissionDefinitionManager : PermissionDefinitionManager +{ + private readonly IStaticPermissionDefinitionStore _staticStore; + private readonly IDynamicPermissionDefinitionStore _dynamicStore; + + public MergePermissionDefinitionManager( + IStaticPermissionDefinitionStore staticStore, + IDynamicPermissionDefinitionStore dynamicStore) : base(staticStore, dynamicStore) + { + _staticStore = staticStore; + _dynamicStore = dynamicStore; + } + + public async override Task> GetGroupsAsync() + { + var staticGroups = await _staticStore.GetGroupsAsync(); + var dynamicGroups = await _dynamicStore.GetGroupsAsync(); + + var mergedGroups = new Dictionary(); + + foreach (var staticGroup in staticGroups) + { + mergedGroups[staticGroup.Name] = staticGroup; + } + + foreach (var dynamicGroup in dynamicGroups) + { + if (mergedGroups.TryGetValue(dynamicGroup.Name, out var existingGroup)) + { + MergeGroupPermissions(existingGroup, dynamicGroup); + } + else + { + mergedGroups[dynamicGroup.Name] = dynamicGroup; + } + } + + return mergedGroups.Values.ToImmutableList(); + } + + private static void MergeGroupPermissions(PermissionGroupDefinition target, PermissionGroupDefinition source) + { + foreach (var sourcePermission in source.Permissions) + { + var existingPermission = target.GetPermissionOrNull(sourcePermission.Name); + + if (existingPermission == null) + { + var newPermission = target.AddPermission( + sourcePermission.Name, + sourcePermission.DisplayName, + sourcePermission.MultiTenancySide, + sourcePermission.IsEnabled + ); + + CopyPermissionDetails(sourcePermission, newPermission); + + foreach (var child in sourcePermission.Children) + { + AddChildPermissionRecursively(newPermission, child); + } + } + else + { + MergePermissionMetadata(existingPermission, sourcePermission); + + foreach (var sourceChild in sourcePermission.Children) + { + MergeChildPermissions(existingPermission, sourceChild); + } + } + } + } + + private static void AddChildPermissionRecursively(PermissionDefinition parent, PermissionDefinition sourceChild) + { + var newChild = parent.AddChild( + sourceChild.Name, + sourceChild.DisplayName, + sourceChild.MultiTenancySide, + sourceChild.IsEnabled + ); + + CopyPermissionDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildPermissionRecursively(newChild, grandchild); + } + } + + private static void MergeChildPermissions(PermissionDefinition parent, PermissionDefinition sourceChild) + { + var existingChild = parent.Children.FirstOrDefault(c => c.Name == sourceChild.Name); + + if (existingChild == null) + { + var newChild = parent.AddChild( + sourceChild.Name, + sourceChild.DisplayName, + sourceChild.MultiTenancySide, + sourceChild.IsEnabled + ); + CopyPermissionDetails(sourceChild, newChild); + + foreach (var grandchild in sourceChild.Children) + { + AddChildPermissionRecursively(newChild, grandchild); + } + } + else + { + MergePermissionMetadata(existingChild, sourceChild); + + foreach (var grandchild in sourceChild.Children) + { + MergeChildPermissions(existingChild, grandchild); + } + } + } + + private static void CopyPermissionDetails(PermissionDefinition source, PermissionDefinition target) + { + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.Providers) + { + if (!target.Providers.Contains(provider)) + { + target.Providers.Add(provider); + } + } + + foreach (var checker in source.StateCheckers) + { + if (!target.StateCheckers.Contains(checker)) + { + target.StateCheckers.Add(checker); + } + } + } + + private static void MergePermissionMetadata(PermissionDefinition target, PermissionDefinition source) + { + target.DisplayName = source.DisplayName; + + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.Providers) + { + if (!target.Providers.Contains(provider)) + { + target.Providers.Add(provider); + } + } + + foreach (var checker in source.StateCheckers) + { + if (!target.StateCheckers.Contains(checker)) + { + target.StateCheckers.Add(checker); + } + } + + if (source.MultiTenancySide != MultiTenancySides.Both) + { + target.MultiTenancySide |= source.MultiTenancySide; + } + + target.IsEnabled = target.IsEnabled || source.IsEnabled; + } +} diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeSettingDefinitionManager.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeSettingDefinitionManager.cs new file mode 100644 index 000000000..0fa2047d9 --- /dev/null +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeSettingDefinitionManager.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Settings; + +namespace LY.MicroService.BackendAdmin.Overrides; + +[Dependency(ReplaceServices = true)] +public class MergeSettingDefinitionManager : SettingDefinitionManager +{ + private readonly IStaticSettingDefinitionStore _staticStore; + private readonly IDynamicSettingDefinitionStore _dynamicStore; + + public MergeSettingDefinitionManager( + IStaticSettingDefinitionStore staticStore, + IDynamicSettingDefinitionStore dynamicStore) + : base(staticStore, dynamicStore) + { + _staticStore = staticStore; + _dynamicStore = dynamicStore; + } + + public async override Task> GetAllAsync() + { + var staticSettings = await _staticStore.GetAllAsync(); + var dynamicSettings = await _dynamicStore.GetAllAsync(); + + var mergedSettings = new Dictionary(); + + foreach (var staticSetting in staticSettings) + { + mergedSettings[staticSetting.Name] = staticSetting; + } + + foreach (var dynamicSetting in dynamicSettings) + { + if (mergedSettings.TryGetValue(dynamicSetting.Name, out var existingSetting)) + { + MergeSetting(existingSetting, dynamicSetting); + } + else + { + mergedSettings[dynamicSetting.Name] = dynamicSetting; + } + } + + return mergedSettings.Values.ToImmutableList(); + } + + private static void MergeSetting(SettingDefinition target, SettingDefinition source) + { + target.DisplayName = source.DisplayName; + target.Description = source.Description ?? target.Description; + target.DefaultValue = source.DefaultValue ?? target.DefaultValue; + target.IsVisibleToClients = target.IsVisibleToClients || source.IsVisibleToClients; + target.IsInherited = target.IsInherited || source.IsInherited; + target.IsEncrypted = target.IsEncrypted || source.IsEncrypted; + + foreach (var property in source.Properties) + { + target.Properties[property.Key] = property.Value; + } + + foreach (var provider in source.Providers) + { + if (!target.Providers.Contains(provider)) + { + target.Providers.Add(provider); + } + } + } +} diff --git a/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeTemplateDefinitionManager.cs b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeTemplateDefinitionManager.cs new file mode 100644 index 000000000..79d3edd07 --- /dev/null +++ b/aspnet-core/services/LY.MicroService.BackendAdmin.HttpApi.Host/Overrides/MergeTemplateDefinitionManager.cs @@ -0,0 +1,85 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.TextTemplating; + +namespace LY.MicroService.BackendAdmin.Overrides; + +[Dependency(ReplaceServices = true)] +public class MergeTemplateDefinitionManager : TemplateDefinitionManager +{ + public MergeTemplateDefinitionManager( + IStaticTemplateDefinitionStore staticStore, + IDynamicTemplateDefinitionStore dynamicStore) + : base(staticStore, dynamicStore) + { + } + public async override Task> GetAllAsync() + { + var staticTemplates = await StaticStore.GetAllAsync(); + var dynamicTemplates = await DynamicStore.GetAllAsync(); + + var mergedTemplates = new Dictionary(); + + foreach (var staticTemplate in staticTemplates) + { + mergedTemplates[staticTemplate.Name] = staticTemplate; + } + + foreach (var dynamicTemplate in dynamicTemplates) + { + if (mergedTemplates.TryGetValue(dynamicTemplate.Name, out var existingTemplate)) + { + MergeTemplate(existingTemplate, dynamicTemplate); + } + else + { + mergedTemplates[dynamicTemplate.Name] = dynamicTemplate; + } + } + + return mergedTemplates.Values.ToImmutableList(); + } + + private static TemplateDefinition MergeTemplate(TemplateDefinition staticTemplate, TemplateDefinition dynamicTemplate) + { + var localizationResourceName = dynamicTemplate.LocalizationResourceName ?? staticTemplate.LocalizationResourceName; + var defaultCultureName = dynamicTemplate.DefaultCultureName ?? staticTemplate.DefaultCultureName; + var displayName = dynamicTemplate.DisplayName ?? staticTemplate.DisplayName; + var isLayout = dynamicTemplate.IsLayout || staticTemplate.IsLayout; + var layout = dynamicTemplate.Layout ?? staticTemplate.Layout; + + var mergedTemplate = new TemplateDefinition( + staticTemplate.Name, + localizationResourceName, + displayName, + isLayout, + layout, + defaultCultureName + ); + + foreach (var property in staticTemplate.Properties) + { + mergedTemplate.Properties[property.Key] = property.Value; + } + + foreach (var property in dynamicTemplate.Properties) + { + mergedTemplate.Properties[property.Key] = property.Value; + } + + if (!string.IsNullOrEmpty(dynamicTemplate.RenderEngine)) + { + mergedTemplate.RenderEngine = dynamicTemplate.RenderEngine; + } + else if (!string.IsNullOrEmpty(staticTemplate.RenderEngine)) + { + mergedTemplate.RenderEngine = staticTemplate.RenderEngine; + } + + mergedTemplate.IsInlineLocalized = dynamicTemplate.IsInlineLocalized || staticTemplate.IsInlineLocalized; + + return mergedTemplate; + } +}