8 changed files with 775 additions and 0 deletions
@ -0,0 +1,3 @@ |
|||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
|
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
|
</Weavers> |
||||
@ -0,0 +1,30 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
||||
|
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
||||
|
<xs:element name="Weavers"> |
||||
|
<xs:complexType> |
||||
|
<xs:all> |
||||
|
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
||||
|
<xs:complexType> |
||||
|
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:all> |
||||
|
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
||||
|
<xs:annotation> |
||||
|
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
||||
|
</xs:annotation> |
||||
|
</xs:attribute> |
||||
|
</xs:complexType> |
||||
|
</xs:element> |
||||
|
</xs:schema> |
||||
@ -0,0 +1,27 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\..\configureawait.props" /> |
||||
|
<Import Project="..\..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0;net10.0</TargetFrameworks> |
||||
|
<AssemblyName>LINGYUN.Abp.Dynamic.Definitions</AssemblyName> |
||||
|
<PackageId>LINGYUN.Abp.Dynamic.Definitions</PackageId> |
||||
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
||||
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
||||
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Authorization" /> |
||||
|
<PackageReference Include="Volo.Abp.Features" /> |
||||
|
<PackageReference Include="Volo.Abp.Settings" /> |
||||
|
<PackageReference Include="Volo.Abp.TextTemplating.Core" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.Dynamic.Definitions.Core\LINGYUN.Abp.Dynamic.Definitions.Core.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,32 @@ |
|||||
|
using Volo.Abp.Authorization; |
||||
|
using Volo.Abp.Authorization.Permissions; |
||||
|
using Volo.Abp.Features; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Settings; |
||||
|
using Volo.Abp.TextTemplating; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dynamic.Definitions; |
||||
|
|
||||
|
[DependsOn( |
||||
|
typeof(AbpFeaturesModule), |
||||
|
typeof(AbpAuthorizationModule), |
||||
|
typeof(AbpTextTemplatingCoreModule), |
||||
|
typeof(AbpDynamicDefinitionsCoreModule))] |
||||
|
public class AbpDynamicDefinitionsModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpDynamicDefinitionsOptions>(options => |
||||
|
{ |
||||
|
options.MapStrategy<FeatureDefinition>(DynamicDefinitionStrategy.Merge); |
||||
|
options.MapStrategy<FeatureGroupDefinition>(DynamicDefinitionStrategy.Merge); |
||||
|
|
||||
|
options.MapStrategy<PermissionDefinition>(DynamicDefinitionStrategy.Merge); |
||||
|
options.MapStrategy<PermissionGroupDefinition>(DynamicDefinitionStrategy.Merge); |
||||
|
|
||||
|
options.MapStrategy<SettingDefinition>(DynamicDefinitionStrategy.Merge); |
||||
|
|
||||
|
options.MapStrategy<TemplateDefinition>(DynamicDefinitionStrategy.Merge); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,253 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Features; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dynamic.Definitions; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices( |
||||
|
typeof(IFeatureDefinitionManager), |
||||
|
typeof(FeatureDynamicDefinitionManager))] |
||||
|
public class FeatureDynamicDefinitionManager : |
||||
|
DynamicDefinitionManager<FeatureGroupDefinition, FeatureDefinition>, |
||||
|
IFeatureDefinitionManager, |
||||
|
ISingletonDependency |
||||
|
{ |
||||
|
protected IStaticFeatureDefinitionStore StaticStore { get; } |
||||
|
protected IDynamicFeatureDefinitionStore DynamicStore { get; } |
||||
|
public FeatureDynamicDefinitionManager( |
||||
|
IStaticFeatureDefinitionStore staticStore, |
||||
|
IDynamicFeatureDefinitionStore dynamicStore, |
||||
|
IOptions<AbpDynamicDefinitionsOptions> options) |
||||
|
: base(options) |
||||
|
{ |
||||
|
StaticStore = staticStore; |
||||
|
DynamicStore = dynamicStore; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IReadOnlyList<FeatureDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
var staticDefinitions = await StaticStore.GetFeaturesAsync(); |
||||
|
var dynamicDefinitions = await DynamicStore.GetFeaturesAsync(); |
||||
|
|
||||
|
return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<FeatureDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
return await GetOrNullAsync(name) ?? throw new AbpException("Undefined feature: " + name); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IReadOnlyList<FeatureGroupDefinition>> GetGroupsAsync() |
||||
|
{ |
||||
|
var staticGroupDefinitions = await StaticStore.GetGroupsAsync(); |
||||
|
var dynamicGroupDefinitions = await DynamicStore.GetGroupsAsync(); |
||||
|
|
||||
|
return await GetGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<FeatureDefinition?> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
var staticDefinition = await StaticStore.GetOrNullAsync(name); |
||||
|
var dynamicDefinition = await DynamicStore.GetOrNullAsync(name); |
||||
|
|
||||
|
return await GetDefinitionAsync(staticDefinition, dynamicDefinition); |
||||
|
} |
||||
|
|
||||
|
protected override string GetDefinitionKey(FeatureDefinition definition) |
||||
|
{ |
||||
|
return definition.Name; |
||||
|
} |
||||
|
|
||||
|
protected override string GetGroupDefinitionKey(FeatureGroupDefinition groupDefinition) |
||||
|
{ |
||||
|
return groupDefinition.Name; |
||||
|
} |
||||
|
|
||||
|
protected override Task<FeatureDefinition> MergeDefinitionAsync(FeatureDefinition targetDefinition, FeatureDefinition sourceDefinition) |
||||
|
{ |
||||
|
targetDefinition.DisplayName = sourceDefinition.DisplayName; |
||||
|
|
||||
|
if (sourceDefinition.Description != null) |
||||
|
{ |
||||
|
targetDefinition.Description = sourceDefinition.Description; |
||||
|
} |
||||
|
|
||||
|
if (sourceDefinition.DefaultValue != null) |
||||
|
{ |
||||
|
targetDefinition.DefaultValue = sourceDefinition.DefaultValue; |
||||
|
} |
||||
|
|
||||
|
if (sourceDefinition.ValueType != null) |
||||
|
{ |
||||
|
targetDefinition.ValueType = sourceDefinition.ValueType; |
||||
|
} |
||||
|
|
||||
|
targetDefinition.IsVisibleToClients = targetDefinition.IsVisibleToClients || sourceDefinition.IsVisibleToClients; |
||||
|
targetDefinition.IsAvailableToHost = targetDefinition.IsAvailableToHost || sourceDefinition.IsAvailableToHost; |
||||
|
|
||||
|
CopyFeatureDetails(targetDefinition, sourceDefinition); |
||||
|
|
||||
|
return Task.FromResult(targetDefinition); |
||||
|
} |
||||
|
|
||||
|
protected async override Task AfterMergeDefinitionAsync(FeatureDefinition targetDefinition, FeatureDefinition sourceDefinition) |
||||
|
{ |
||||
|
foreach (var child in sourceDefinition.Children) |
||||
|
{ |
||||
|
await MergeChildFeature(targetDefinition, child); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected async override Task MergeGroupDefinitionAsync(FeatureGroupDefinition targetGroupDefinition, FeatureGroupDefinition sourceGroupDefinition) |
||||
|
{ |
||||
|
if (sourceGroupDefinition.DisplayName != null) |
||||
|
{ |
||||
|
targetGroupDefinition.DisplayName = sourceGroupDefinition.DisplayName; |
||||
|
} |
||||
|
foreach (var property in sourceGroupDefinition.Properties) |
||||
|
{ |
||||
|
targetGroupDefinition.Properties[property.Key] = property.Value; |
||||
|
} |
||||
|
|
||||
|
foreach (var sourceFeature in sourceGroupDefinition.Features) |
||||
|
{ |
||||
|
var existingFeature = GetFeatureOrNull(targetGroupDefinition, sourceFeature.Name); |
||||
|
|
||||
|
if (existingFeature == null) |
||||
|
{ |
||||
|
var newFeature = targetGroupDefinition.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 |
||||
|
{ |
||||
|
await MergeDefinitionAsync(existingFeature, sourceFeature); |
||||
|
|
||||
|
foreach (var child in sourceFeature.Children) |
||||
|
{ |
||||
|
await MergeChildFeature(existingFeature, child); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private async Task 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 |
||||
|
{ |
||||
|
await MergeDefinitionAsync(existingChild, sourceChild); |
||||
|
|
||||
|
foreach (var grandchild in sourceChild.Children) |
||||
|
{ |
||||
|
await MergeChildFeature(existingChild, grandchild); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
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 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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static FeatureDefinition? GetFeatureOrNull( |
||||
|
FeatureGroupDefinition group, |
||||
|
[NotNull] string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
return GetFeatureOrNullRecursively(group.Features, name); |
||||
|
} |
||||
|
|
||||
|
private static FeatureDefinition? GetFeatureOrNullRecursively( |
||||
|
IReadOnlyList<FeatureDefinition> features, |
||||
|
string name) |
||||
|
{ |
||||
|
foreach (var feature in features) |
||||
|
{ |
||||
|
if (feature.Name == name) |
||||
|
{ |
||||
|
return feature; |
||||
|
} |
||||
|
|
||||
|
var childFeature = GetFeatureOrNullRecursively(feature.Children, name); |
||||
|
if (childFeature != null) |
||||
|
{ |
||||
|
return childFeature; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,249 @@ |
|||||
|
using Microsoft.Extensions.Options; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Authorization.Permissions; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dynamic.Definitions; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices( |
||||
|
typeof(IPermissionDefinitionManager), |
||||
|
typeof(PermissionDynamicDefinitionManager))] |
||||
|
public class PermissionDynamicDefinitionManager : |
||||
|
DynamicDefinitionManager<PermissionGroupDefinition, PermissionDefinition>, |
||||
|
IPermissionDefinitionManager, |
||||
|
ITransientDependency |
||||
|
{ |
||||
|
protected IStaticPermissionDefinitionStore StaticStore { get; } |
||||
|
protected IDynamicPermissionDefinitionStore DynamicStore { get; } |
||||
|
public PermissionDynamicDefinitionManager( |
||||
|
IStaticPermissionDefinitionStore staticStore, |
||||
|
IDynamicPermissionDefinitionStore dynamicStore, |
||||
|
IOptions<AbpDynamicDefinitionsOptions> options) : base(options) |
||||
|
{ |
||||
|
StaticStore = staticStore; |
||||
|
DynamicStore = dynamicStore; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<PermissionDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
return await GetOrNullAsync(name) ?? throw new AbpException("Undefined permission: " + name); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync() |
||||
|
{ |
||||
|
var staticGroupDefinitions = await StaticStore.GetGroupsAsync(); |
||||
|
var dynamicGroupDefinitions = await DynamicStore.GetGroupsAsync(); |
||||
|
|
||||
|
return await GetGroupDefinitionsAsync(staticGroupDefinitions, dynamicGroupDefinitions); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<PermissionDefinition?> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
var staticDefinition = await StaticStore.GetOrNullAsync(name); |
||||
|
var dynamicDefinition = await DynamicStore.GetOrNullAsync(name); |
||||
|
|
||||
|
return await GetDefinitionAsync(staticDefinition, dynamicDefinition); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync() |
||||
|
{ |
||||
|
var staticDefinitions = await StaticStore.GetPermissionsAsync(); |
||||
|
var dynamicDefinitions = await DynamicStore.GetPermissionsAsync(); |
||||
|
|
||||
|
return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<PermissionDefinition> GetResourcePermissionAsync(string resourceName, string name) |
||||
|
{ |
||||
|
return await GetResourcePermissionOrNullAsync(resourceName, name) |
||||
|
?? throw new AbpException($"Undefined resource permission: {name} for resource: {resourceName}"); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string resourceName, string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
var staticDefinition = await StaticStore.GetResourcePermissionOrNullAsync(resourceName, name); |
||||
|
var dynamicDefinition = await DynamicStore.GetResourcePermissionOrNullAsync(resourceName, name); |
||||
|
|
||||
|
return await GetDefinitionAsync(staticDefinition, dynamicDefinition); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync() |
||||
|
{ |
||||
|
var staticDefinitions = await StaticStore.GetResourcePermissionsAsync(); |
||||
|
var dynamicDefinitions = await DynamicStore.GetResourcePermissionsAsync(); |
||||
|
|
||||
|
return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions); |
||||
|
} |
||||
|
|
||||
|
protected override string GetDefinitionKey(PermissionDefinition definition) |
||||
|
{ |
||||
|
return definition.Name; |
||||
|
} |
||||
|
|
||||
|
protected override string GetGroupDefinitionKey(PermissionGroupDefinition groupDefinition) |
||||
|
{ |
||||
|
return groupDefinition.Name; |
||||
|
} |
||||
|
|
||||
|
protected override Task<PermissionDefinition> MergeDefinitionAsync(PermissionDefinition targetDefinition, PermissionDefinition sourceDefinition) |
||||
|
{ |
||||
|
targetDefinition.DisplayName = sourceDefinition.DisplayName; |
||||
|
if (sourceDefinition.ResourceName != null) |
||||
|
{ |
||||
|
targetDefinition.ResourceName = sourceDefinition.ResourceName; |
||||
|
} |
||||
|
if (sourceDefinition.ManagementPermissionName != null) |
||||
|
{ |
||||
|
targetDefinition.ManagementPermissionName = sourceDefinition.ManagementPermissionName; |
||||
|
} |
||||
|
|
||||
|
if (sourceDefinition.MultiTenancySide != MultiTenancySides.Both) |
||||
|
{ |
||||
|
targetDefinition.MultiTenancySide |= sourceDefinition.MultiTenancySide; |
||||
|
} |
||||
|
|
||||
|
targetDefinition.IsEnabled = targetDefinition.IsEnabled || sourceDefinition.IsEnabled; |
||||
|
|
||||
|
CopyPermissionDetails(targetDefinition, sourceDefinition); |
||||
|
|
||||
|
return Task.FromResult(targetDefinition); |
||||
|
} |
||||
|
|
||||
|
protected async override Task MergeGroupDefinitionAsync(PermissionGroupDefinition targetGroupDefinition, PermissionGroupDefinition sourceGroupDefinition) |
||||
|
{ |
||||
|
if (sourceGroupDefinition.DisplayName != null) |
||||
|
{ |
||||
|
targetGroupDefinition.DisplayName = sourceGroupDefinition.DisplayName; |
||||
|
} |
||||
|
foreach (var property in sourceGroupDefinition.Properties) |
||||
|
{ |
||||
|
targetGroupDefinition.Properties[property.Key] = property.Value; |
||||
|
} |
||||
|
|
||||
|
foreach (var sourcePermission in sourceGroupDefinition.Permissions) |
||||
|
{ |
||||
|
var existingPermission = targetGroupDefinition.GetPermissionOrNull(sourcePermission.Name); |
||||
|
|
||||
|
if (existingPermission == null) |
||||
|
{ |
||||
|
var newPermission = targetGroupDefinition.AddPermission( |
||||
|
sourcePermission.Name, |
||||
|
sourcePermission.DisplayName, |
||||
|
sourcePermission.MultiTenancySide, |
||||
|
sourcePermission.IsEnabled |
||||
|
); |
||||
|
newPermission.ResourceName = sourcePermission.ResourceName; |
||||
|
newPermission.ManagementPermissionName = sourcePermission.ManagementPermissionName; |
||||
|
|
||||
|
CopyPermissionDetails(sourcePermission, newPermission); |
||||
|
|
||||
|
foreach (var child in sourcePermission.Children) |
||||
|
{ |
||||
|
AddChildPermissionRecursively(newPermission, child); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
await MergeDefinitionAsync(existingPermission, sourcePermission); |
||||
|
|
||||
|
foreach (var sourceChild in sourcePermission.Children) |
||||
|
{ |
||||
|
await MergeChildPermissions(existingPermission, sourceChild); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected async override Task AfterMergeDefinitionAsync(PermissionDefinition targetDefinition, PermissionDefinition sourceDefinition) |
||||
|
{ |
||||
|
foreach (var child in sourceDefinition.Children) |
||||
|
{ |
||||
|
await MergeChildPermissions(targetDefinition, child); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private async Task 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 |
||||
|
); |
||||
|
newChild.ResourceName = sourceChild.ResourceName; |
||||
|
newChild.ManagementPermissionName = sourceChild.ManagementPermissionName; |
||||
|
|
||||
|
CopyPermissionDetails(sourceChild, newChild); |
||||
|
|
||||
|
foreach (var grandchild in sourceChild.Children) |
||||
|
{ |
||||
|
AddChildPermissionRecursively(newChild, grandchild); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
await MergeDefinitionAsync(existingChild, sourceChild); |
||||
|
|
||||
|
foreach (var grandchild in sourceChild.Children) |
||||
|
{ |
||||
|
await MergeChildPermissions(existingChild, grandchild); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static void AddChildPermissionRecursively(PermissionDefinition parent, PermissionDefinition sourceChild) |
||||
|
{ |
||||
|
var newChild = parent.AddChild( |
||||
|
sourceChild.Name, |
||||
|
sourceChild.DisplayName, |
||||
|
sourceChild.MultiTenancySide, |
||||
|
sourceChild.IsEnabled |
||||
|
); |
||||
|
newChild.ResourceName = sourceChild.ResourceName; |
||||
|
newChild.ManagementPermissionName = sourceChild.ManagementPermissionName; |
||||
|
|
||||
|
CopyPermissionDetails(sourceChild, newChild); |
||||
|
|
||||
|
foreach (var grandchild in sourceChild.Children) |
||||
|
{ |
||||
|
AddChildPermissionRecursively(newChild, 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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
using Microsoft.Extensions.Options; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Settings; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dynamic.Definitions; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices( |
||||
|
typeof(ISettingDefinitionManager), |
||||
|
typeof(SettingDynamicDefinitionManager))] |
||||
|
public class SettingDynamicDefinitionManager : |
||||
|
DynamicDefinitionManager<SettingDefinition>, |
||||
|
ISettingDefinitionManager, |
||||
|
ISingletonDependency |
||||
|
{ |
||||
|
protected IStaticSettingDefinitionStore StaticStore { get; } |
||||
|
protected IDynamicSettingDefinitionStore DynamicStore { get; } |
||||
|
public SettingDynamicDefinitionManager( |
||||
|
IStaticSettingDefinitionStore staticStore, |
||||
|
IDynamicSettingDefinitionStore dynamicStore, |
||||
|
IOptions<AbpDynamicDefinitionsOptions> options) : base(options) |
||||
|
{ |
||||
|
StaticStore = staticStore; |
||||
|
DynamicStore = dynamicStore; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IReadOnlyList<SettingDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
var staticDefinitions = await StaticStore.GetAllAsync(); |
||||
|
var dynamicDefinitions = await DynamicStore.GetAllAsync(); |
||||
|
|
||||
|
return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<SettingDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
return await GetOrNullAsync(name) ?? throw new AbpException("Undefined setting: " + name); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<SettingDefinition?> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
var staticDefinition = await StaticStore.GetOrNullAsync(name); |
||||
|
var dynamicDefinition = await DynamicStore.GetOrNullAsync(name); |
||||
|
|
||||
|
return await GetDefinitionAsync(staticDefinition, dynamicDefinition); |
||||
|
} |
||||
|
|
||||
|
protected override string GetDefinitionKey(SettingDefinition definition) |
||||
|
{ |
||||
|
return definition.Name; |
||||
|
} |
||||
|
|
||||
|
protected override Task<SettingDefinition> MergeDefinitionAsync(SettingDefinition targetDefinition, SettingDefinition sourceDefinition) |
||||
|
{ |
||||
|
targetDefinition.DisplayName = sourceDefinition.DisplayName; |
||||
|
targetDefinition.Description = sourceDefinition.Description ?? targetDefinition.Description; |
||||
|
targetDefinition.DefaultValue = sourceDefinition.DefaultValue ?? targetDefinition.DefaultValue; |
||||
|
targetDefinition.IsVisibleToClients = targetDefinition.IsVisibleToClients || sourceDefinition.IsVisibleToClients; |
||||
|
targetDefinition.IsInherited = targetDefinition.IsInherited || sourceDefinition.IsInherited; |
||||
|
targetDefinition.IsEncrypted = targetDefinition.IsEncrypted || sourceDefinition.IsEncrypted; |
||||
|
|
||||
|
foreach (var property in sourceDefinition.Properties) |
||||
|
{ |
||||
|
targetDefinition.Properties[property.Key] = property.Value; |
||||
|
} |
||||
|
|
||||
|
foreach (var provider in sourceDefinition.Providers) |
||||
|
{ |
||||
|
if (!targetDefinition.Providers.Contains(provider)) |
||||
|
{ |
||||
|
targetDefinition.Providers.Add(provider); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Task.FromResult(targetDefinition); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,99 @@ |
|||||
|
using Microsoft.Extensions.Options; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.TextTemplating; |
||||
|
|
||||
|
namespace LINGYUN.Abp.Dynamic.Definitions; |
||||
|
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
[ExposeServices( |
||||
|
typeof(ITemplateDefinitionManager), |
||||
|
typeof(TemplateDynamicDefinitionManager))] |
||||
|
public class TemplateDynamicDefinitionManager : |
||||
|
DynamicDefinitionManager<TemplateDefinition>, |
||||
|
ITemplateDefinitionManager, |
||||
|
ISingletonDependency |
||||
|
{ |
||||
|
protected IStaticTemplateDefinitionStore StaticStore { get; } |
||||
|
protected IDynamicTemplateDefinitionStore DynamicStore { get; } |
||||
|
|
||||
|
public TemplateDynamicDefinitionManager( |
||||
|
IStaticTemplateDefinitionStore staticStore, |
||||
|
IDynamicTemplateDefinitionStore dynamicStore, |
||||
|
IOptions<AbpDynamicDefinitionsOptions> options) : base(options) |
||||
|
{ |
||||
|
StaticStore = staticStore; |
||||
|
DynamicStore = dynamicStore; |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<IReadOnlyList<TemplateDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
var staticDefinitions = await StaticStore.GetAllAsync(); |
||||
|
var dynamicDefinitions = await DynamicStore.GetAllAsync(); |
||||
|
|
||||
|
return await GetDefinitionsAsync(staticDefinitions, dynamicDefinitions); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<TemplateDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
return await GetOrNullAsync(name) ?? throw new AbpException("Undefined Template: " + name); |
||||
|
} |
||||
|
|
||||
|
public async virtual Task<TemplateDefinition?> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
var staticDefinition = await StaticStore.GetOrNullAsync(name); |
||||
|
var dynamicDefinition = await DynamicStore.GetOrNullAsync(name); |
||||
|
|
||||
|
return await GetDefinitionAsync(staticDefinition, dynamicDefinition); |
||||
|
} |
||||
|
|
||||
|
protected override string GetDefinitionKey(TemplateDefinition definition) |
||||
|
{ |
||||
|
return definition.Name; |
||||
|
} |
||||
|
|
||||
|
protected override Task<TemplateDefinition> MergeDefinitionAsync(TemplateDefinition targetDefinition, TemplateDefinition sourceDefinition) |
||||
|
{ |
||||
|
var localizationResourceName = sourceDefinition.LocalizationResourceName ?? targetDefinition.LocalizationResourceName; |
||||
|
var defaultCultureName = sourceDefinition.DefaultCultureName ?? targetDefinition.DefaultCultureName; |
||||
|
var displayName = sourceDefinition.DisplayName ?? targetDefinition.DisplayName; |
||||
|
var isLayout = sourceDefinition.IsLayout || targetDefinition.IsLayout; |
||||
|
var layout = sourceDefinition.Layout ?? targetDefinition.Layout; |
||||
|
|
||||
|
var mergedTemplate = new TemplateDefinition( |
||||
|
targetDefinition.Name, |
||||
|
localizationResourceName, |
||||
|
displayName, |
||||
|
isLayout, |
||||
|
layout, |
||||
|
defaultCultureName |
||||
|
); |
||||
|
|
||||
|
foreach (var property in targetDefinition.Properties) |
||||
|
{ |
||||
|
mergedTemplate.Properties[property.Key] = property.Value; |
||||
|
} |
||||
|
|
||||
|
foreach (var property in sourceDefinition.Properties) |
||||
|
{ |
||||
|
mergedTemplate.Properties[property.Key] = property.Value; |
||||
|
} |
||||
|
|
||||
|
if (!string.IsNullOrEmpty(sourceDefinition.RenderEngine)) |
||||
|
{ |
||||
|
mergedTemplate.RenderEngine = sourceDefinition.RenderEngine; |
||||
|
} |
||||
|
else if (!string.IsNullOrEmpty(targetDefinition.RenderEngine)) |
||||
|
{ |
||||
|
mergedTemplate.RenderEngine = targetDefinition.RenderEngine; |
||||
|
} |
||||
|
|
||||
|
mergedTemplate.IsInlineLocalized = sourceDefinition.IsInlineLocalized || targetDefinition.IsInlineLocalized; |
||||
|
|
||||
|
return Task.FromResult(mergedTemplate); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue