mirror of https://github.com/abpframework/abp.git
34 changed files with 444 additions and 104 deletions
@ -0,0 +1,8 @@ |
|||||
|
# ABP Version 7.4 Migration Guide |
||||
|
|
||||
|
This document is a guide for upgrading ABP v7.3 solutions to ABP v7.4. There are a few changes in this version that may affect your applications, please read it carefully and apply the necessary changes to your application. |
||||
|
|
||||
|
## TemplateDefinition |
||||
|
|
||||
|
The `LocalizationResource(Type)` of `TemplateDefinition` class is changed to `LocalizationResourceName(string)`. |
||||
|
|
||||
@ -0,0 +1,14 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating; |
||||
|
|
||||
|
public interface IDynamicTemplateDefinitionStore |
||||
|
{ |
||||
|
Task<TemplateDefinition> GetAsync([NotNull] string name); |
||||
|
|
||||
|
Task<IReadOnlyList<TemplateDefinition>> GetAllAsync(); |
||||
|
|
||||
|
Task<TemplateDefinition> GetOrNullAsync(string name); |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating; |
||||
|
|
||||
|
public interface IStaticTemplateDefinitionStore |
||||
|
{ |
||||
|
Task<TemplateDefinition> GetAsync([NotNull] string name); |
||||
|
|
||||
|
Task<IReadOnlyList<TemplateDefinition>> GetAllAsync(); |
||||
|
|
||||
|
Task<TemplateDefinition> GetOrNullAsync(string name); |
||||
|
} |
||||
@ -1,16 +1,17 @@ |
|||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
using JetBrains.Annotations; |
using JetBrains.Annotations; |
||||
|
|
||||
namespace Volo.Abp.TextTemplating; |
namespace Volo.Abp.TextTemplating; |
||||
|
|
||||
public interface ITemplateDefinitionManager |
public interface ITemplateDefinitionManager |
||||
{ |
{ |
||||
[NotNull] |
[ItemNotNull] |
||||
TemplateDefinition Get([NotNull] string name); |
Task<TemplateDefinition> GetAsync([NotNull] string name); |
||||
|
|
||||
[NotNull] |
[ItemNotNull] |
||||
IReadOnlyList<TemplateDefinition> GetAll(); |
Task<IReadOnlyList<TemplateDefinition>> GetAllAsync(); |
||||
|
|
||||
[CanBeNull] |
[ItemCanBeNull] |
||||
TemplateDefinition GetOrNull(string name); |
Task<TemplateDefinition> GetOrNullAsync(string name); |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,29 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Immutable; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating; |
||||
|
|
||||
|
public class NullIDynamicTemplateDefinitionStore : IDynamicTemplateDefinitionStore, ISingletonDependency |
||||
|
{ |
||||
|
private readonly static Task<TemplateDefinition> CachedTemplateResult = Task.FromResult((TemplateDefinition)null); |
||||
|
|
||||
|
private readonly static Task<IReadOnlyList<TemplateDefinition>> CachedFeaturesResult = Task.FromResult((IReadOnlyList<TemplateDefinition>)Array.Empty<TemplateDefinition>().ToImmutableList()); |
||||
|
|
||||
|
public Task<TemplateDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
return CachedTemplateResult; |
||||
|
} |
||||
|
|
||||
|
public Task<IReadOnlyList<TemplateDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
return CachedFeaturesResult; |
||||
|
} |
||||
|
|
||||
|
public Task<TemplateDefinition> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
return CachedTemplateResult; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
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.TextTemplating; |
||||
|
|
||||
|
public class StaticTemplateDefinitionStore : IStaticTemplateDefinitionStore, ISingletonDependency |
||||
|
{ |
||||
|
protected Lazy<IDictionary<string, TemplateDefinition>> TemplateDefinitions { get; } |
||||
|
|
||||
|
protected AbpTextTemplatingOptions Options { get; } |
||||
|
|
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public StaticTemplateDefinitionStore(IOptions<AbpTextTemplatingOptions> options, IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
Options = options.Value; |
||||
|
|
||||
|
TemplateDefinitions = new Lazy<IDictionary<string, TemplateDefinition>>(CreateTextTemplateDefinitions, true); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<TemplateDefinition> GetAsync(string name) |
||||
|
{ |
||||
|
Check.NotNull(name, nameof(name)); |
||||
|
|
||||
|
var template = GetOrNullAsync(name); |
||||
|
|
||||
|
if (template == null) |
||||
|
{ |
||||
|
throw new AbpException("Undefined template: " + name); |
||||
|
} |
||||
|
|
||||
|
return template; |
||||
|
} |
||||
|
|
||||
|
public virtual Task<IReadOnlyList<TemplateDefinition>> GetAllAsync() |
||||
|
{ |
||||
|
return Task.FromResult<IReadOnlyList<TemplateDefinition>>(TemplateDefinitions.Value.Values.ToImmutableList()); |
||||
|
} |
||||
|
|
||||
|
public virtual Task<TemplateDefinition> GetOrNullAsync(string name) |
||||
|
{ |
||||
|
return Task.FromResult(TemplateDefinitions.Value.GetOrDefault(name)); |
||||
|
} |
||||
|
|
||||
|
protected virtual IDictionary<string, TemplateDefinition> CreateTextTemplateDefinitions() |
||||
|
{ |
||||
|
var templates = new Dictionary<string, TemplateDefinition>(); |
||||
|
|
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
var providers = Options |
||||
|
.DefinitionProviders |
||||
|
.Select(p => scope.ServiceProvider.GetRequiredService(p) as ITemplateDefinitionProvider) |
||||
|
.ToList(); |
||||
|
|
||||
|
var context = new TemplateDefinitionContext(templates); |
||||
|
|
||||
|
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 templates; |
||||
|
} |
||||
|
} |
||||
@ -1,85 +1,50 @@ |
|||||
using System; |
using System.Collections.Generic; |
||||
using System.Collections.Generic; |
|
||||
using System.Collections.Immutable; |
using System.Collections.Immutable; |
||||
using System.Linq; |
using System.Linq; |
||||
using Microsoft.Extensions.DependencyInjection; |
using System.Threading.Tasks; |
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
namespace Volo.Abp.TextTemplating; |
namespace Volo.Abp.TextTemplating; |
||||
|
|
||||
public class TemplateDefinitionManager : ITemplateDefinitionManager, ISingletonDependency |
public class TemplateDefinitionManager : ITemplateDefinitionManager, ISingletonDependency |
||||
{ |
{ |
||||
protected Lazy<IDictionary<string, TemplateDefinition>> TemplateDefinitions { get; } |
protected readonly IStaticTemplateDefinitionStore StaticStore; |
||||
|
protected readonly IDynamicTemplateDefinitionStore DynamicStore; |
||||
|
|
||||
protected AbpTextTemplatingOptions Options { get; } |
public TemplateDefinitionManager(IStaticTemplateDefinitionStore staticStore, IDynamicTemplateDefinitionStore dynamicStore) |
||||
|
|
||||
protected IServiceProvider ServiceProvider { get; } |
|
||||
|
|
||||
public TemplateDefinitionManager( |
|
||||
IOptions<AbpTextTemplatingOptions> options, |
|
||||
IServiceProvider serviceProvider) |
|
||||
{ |
{ |
||||
ServiceProvider = serviceProvider; |
StaticStore = staticStore; |
||||
Options = options.Value; |
DynamicStore = dynamicStore; |
||||
|
|
||||
TemplateDefinitions = |
|
||||
new Lazy<IDictionary<string, TemplateDefinition>>(CreateTextTemplateDefinitions, true); |
|
||||
} |
} |
||||
|
|
||||
public virtual TemplateDefinition Get(string name) |
public virtual async Task<TemplateDefinition> GetAsync(string name) |
||||
{ |
{ |
||||
Check.NotNull(name, nameof(name)); |
var permission = await GetOrNullAsync(name); |
||||
|
if (permission == null) |
||||
var template = GetOrNull(name); |
|
||||
|
|
||||
if (template == null) |
|
||||
{ |
{ |
||||
throw new AbpException("Undefined template: " + name); |
throw new AbpException("Undefined Template: " + name); |
||||
} |
} |
||||
|
|
||||
return template; |
return permission; |
||||
} |
} |
||||
|
|
||||
public virtual IReadOnlyList<TemplateDefinition> GetAll() |
public virtual async Task<TemplateDefinition> GetOrNullAsync(string name) |
||||
{ |
{ |
||||
return TemplateDefinitions.Value.Values.ToImmutableList(); |
Check.NotNull(name, nameof(name)); |
||||
} |
|
||||
|
|
||||
public virtual TemplateDefinition GetOrNull(string name) |
return await StaticStore.GetOrNullAsync(name) ?? await DynamicStore.GetOrNullAsync(name); |
||||
{ |
|
||||
return TemplateDefinitions.Value.GetOrDefault(name); |
|
||||
} |
} |
||||
|
|
||||
protected virtual IDictionary<string, TemplateDefinition> CreateTextTemplateDefinitions() |
public virtual async Task<IReadOnlyList<TemplateDefinition>> GetAllAsync() |
||||
{ |
{ |
||||
var templates = new Dictionary<string, TemplateDefinition>(); |
var staticTemplates = await StaticStore.GetAllAsync(); |
||||
|
var staticTemplateNames = staticTemplates |
||||
using (var scope = ServiceProvider.CreateScope()) |
.Select(p => p.Name) |
||||
{ |
.ToImmutableHashSet(); |
||||
var providers = Options |
|
||||
.DefinitionProviders |
|
||||
.Select(p => scope.ServiceProvider.GetRequiredService(p) as ITemplateDefinitionProvider) |
|
||||
.ToList(); |
|
||||
|
|
||||
var context = new TemplateDefinitionContext(templates); |
|
||||
|
|
||||
foreach (var provider in providers) |
var dynamicTemplates = await DynamicStore.GetAllAsync(); |
||||
{ |
|
||||
provider.PreDefine(context); |
|
||||
} |
|
||||
|
|
||||
foreach (var provider in providers) |
|
||||
{ |
|
||||
provider.Define(context); |
|
||||
} |
|
||||
|
|
||||
foreach (var provider in providers) |
|
||||
{ |
|
||||
provider.PostDefine(context); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return templates; |
/* We prefer static Templates over dynamics */ |
||||
|
return staticTemplates.Concat(dynamicTemplates.Where(d => !staticTemplateNames.Contains(d.Name))).ToImmutableList(); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,8 @@ |
|||||
|
namespace Volo.Abp.TextTemplating.VirtualFiles; |
||||
|
|
||||
|
public class TemplateContentFileInfo |
||||
|
{ |
||||
|
public string FileName { get; set; } |
||||
|
|
||||
|
public string FileContent { get; set; } |
||||
|
} |
||||
@ -0,0 +1,56 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating.VirtualFiles; |
||||
|
|
||||
|
public class TemplateContentFileProvider : ITransientDependency |
||||
|
{ |
||||
|
protected IVirtualFileProvider VirtualFileProvider { get; } |
||||
|
|
||||
|
public TemplateContentFileProvider(IVirtualFileProvider virtualFileProvider) |
||||
|
{ |
||||
|
VirtualFileProvider = virtualFileProvider; |
||||
|
} |
||||
|
|
||||
|
public async Task<List<TemplateContentFileInfo>> GetFilesAsync(TemplateDefinition templateDefinition) |
||||
|
{ |
||||
|
var files = new List<TemplateContentFileInfo>(); |
||||
|
|
||||
|
var virtualPath = templateDefinition.GetVirtualFilePathOrNull(); |
||||
|
if (virtualPath == null) |
||||
|
{ |
||||
|
return files; |
||||
|
} |
||||
|
|
||||
|
var fileInfo = VirtualFileProvider.GetFileInfo(virtualPath); |
||||
|
if (!fileInfo.Exists) |
||||
|
{ |
||||
|
var directoryContents = VirtualFileProvider.GetDirectoryContents(virtualPath); |
||||
|
if (!directoryContents.Exists) |
||||
|
{ |
||||
|
throw new AbpException("Could not find a file/folder at the location: " + virtualPath); |
||||
|
} |
||||
|
|
||||
|
fileInfo = new VirtualDirectoryFileInfo(virtualPath, virtualPath, DateTimeOffset.UtcNow); |
||||
|
} |
||||
|
|
||||
|
if (fileInfo.IsDirectory) |
||||
|
{ |
||||
|
//TODO: Configure file extensions.
|
||||
|
var folderReader = new VirtualFolderLocalizedTemplateContentReader(new[] { ".tpl", ".cshtml" }); |
||||
|
await folderReader.ReadContentsAsync(VirtualFileProvider, virtualPath); |
||||
|
files.AddRange(folderReader.GetFiles()); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var singleFileReader = new FileInfoLocalizedTemplateContentReader(); |
||||
|
await singleFileReader.ReadContentsAsync(fileInfo); |
||||
|
files.Add(singleFileReader.GetFile()); |
||||
|
} |
||||
|
|
||||
|
return files; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.TextTemplating.VirtualFiles; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating.Razor; |
||||
|
|
||||
|
public class RazorTemplateContentFileProvider_Tests : TemplateContentFileProvider_Tests<RazorTextTemplatingTestModule> |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task GetRazorFilesAsync() |
||||
|
{ |
||||
|
var definition = await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail); |
||||
|
var files = await TemplateContentFileProvider.GetFilesAsync(definition); |
||||
|
files.Count.ShouldBe(2); |
||||
|
files.ShouldContain(x => x.FileName == "en.cshtml" && x.FileContent.Contains("Welcome @Model.Name to the abp.io!")); |
||||
|
files.ShouldContain(x => x.FileName == "tr.cshtml" && x.FileContent.Contains("Merhaba @Model.Name, abp.io'ya hoşgeldiniz!")); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.TextTemplating.VirtualFiles; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating.Scriban.SampleTemplates; |
||||
|
|
||||
|
public class ScribanTemplateContentFileProvider_Tests : TemplateContentFileProvider_Tests<ScribanTextTemplatingTestModule> |
||||
|
{ |
||||
|
[Fact] |
||||
|
public async Task GetScribanFilesAsync() |
||||
|
{ |
||||
|
var definition = await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail); |
||||
|
var files = await TemplateContentFileProvider.GetFilesAsync(definition); |
||||
|
files.Count.ShouldBe(2); |
||||
|
files.ShouldContain(x => x.FileName == "en.tpl" && x.FileContent.Contains("Welcome {{model.name}} to the abp.io!")); |
||||
|
files.ShouldContain(x => x.FileName == "tr.tpl" && x.FileContent.Contains("Merhaba {{model.name}}, abp.io'ya hoşgeldiniz!")); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.TextTemplating.VirtualFiles; |
||||
|
|
||||
|
public abstract class TemplateContentFileProvider_Tests<TStartupModule> : AbpTextTemplatingTestBase<TStartupModule> |
||||
|
where TStartupModule : IAbpModule |
||||
|
{ |
||||
|
protected readonly TemplateContentFileProvider TemplateContentFileProvider; |
||||
|
protected readonly ITemplateDefinitionManager TemplateDefinitionManager; |
||||
|
|
||||
|
protected TemplateContentFileProvider_Tests() |
||||
|
{ |
||||
|
TemplateContentFileProvider = GetRequiredService<TemplateContentFileProvider>(); |
||||
|
TemplateDefinitionManager = GetRequiredService<ITemplateDefinitionManager>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task GetFilesAsync() |
||||
|
{ |
||||
|
var definition = await TemplateDefinitionManager.GetAsync(TestTemplates.HybridTemplateScriban); |
||||
|
|
||||
|
var files = await TemplateContentFileProvider.GetFilesAsync(definition); |
||||
|
files.Count.ShouldBe(1); |
||||
|
files.ShouldContain(x => x.FileName == "TestScribanTemplate.tpl" && x.FileContent == "Hello {{model.name}}, {{L \"HowAreYou\" }}"); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Shouldly; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.OpenIddict.Applications; |
||||
|
|
||||
|
public class AbpApplicationManager_Tests : OpenIddictDomainTestBase |
||||
|
{ |
||||
|
private readonly IAbpApplicationManager _applicationManager; |
||||
|
private readonly AbpOpenIddictTestData _testData; |
||||
|
|
||||
|
public AbpApplicationManager_Tests() |
||||
|
{ |
||||
|
_applicationManager = ServiceProvider.GetRequiredService<IAbpApplicationManager>(); |
||||
|
_testData = ServiceProvider.GetRequiredService<AbpOpenIddictTestData>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Populate_Descriptor_With_Application_Test() |
||||
|
{ |
||||
|
var app1 = (await _applicationManager.FindByClientIdAsync(_testData.App1ClientId)).As<OpenIddictApplicationModel>(); |
||||
|
|
||||
|
var descriptor = new AbpApplicationDescriptor(); |
||||
|
await _applicationManager.PopulateAsync(descriptor, app1); |
||||
|
|
||||
|
app1.ClientUri.ShouldNotBeNull(); |
||||
|
app1.LogoUri.ShouldNotBeNull(); |
||||
|
|
||||
|
descriptor.ClientUri.ShouldBe(app1.ClientUri); |
||||
|
descriptor.LogoUri.ShouldBe(app1.LogoUri); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Populate_Application_With_Descriptor_Test() |
||||
|
{ |
||||
|
var app1 = (await _applicationManager.FindByClientIdAsync(_testData.App1ClientId)).As<OpenIddictApplicationModel>(); |
||||
|
|
||||
|
var descriptor = new AbpApplicationDescriptor() |
||||
|
{ |
||||
|
ClientUri = "https://new.com", |
||||
|
LogoUri = "https://new.com/logo.png" |
||||
|
}; |
||||
|
await _applicationManager.PopulateAsync(app1, descriptor); |
||||
|
|
||||
|
app1.ClientUri.ShouldBe(descriptor.ClientUri); |
||||
|
app1.LogoUri.ShouldBe(descriptor.LogoUri); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue