From 3c7f90decca0b013dd0448d9158be84133ae8386 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 7 Jun 2023 17:24:02 +0800 Subject: [PATCH 01/47] Add `Dynamic Text Template` infrastructure. --- .../Abp/TextTemplating/AbpTemplateRenderer.cs | 2 +- .../AbpTextTemplatingOptions.cs | 3 + .../IDynamicTemplateDefinitionStore.cs | 14 ++++ .../IStaticTemplateDefinitionStore.cs | 14 ++++ .../ITemplateDefinitionManager.cs | 7 +- .../NullIDynamicTemplateDefinitionStore.cs | 29 +++++++ .../StaticTemplateDefinitionStore.cs | 83 +++++++++++++++++++ .../TextTemplating/TemplateContentProvider.cs | 6 +- .../Abp/TextTemplating/TemplateDefinition.cs | 6 +- .../TemplateDefinitionManager.cs | 81 +++++------------- .../TemplateRenderingEngineBase.cs | 4 +- .../FileInfoLocalizedTemplateContentReader.cs | 11 +++ .../VirtualFiles/TemplateContentFileInfo.cs | 8 ++ .../TemplateContentFileProvider.cs | 56 +++++++++++++ ...ualFolderLocalizedTemplateContentReader.cs | 18 +++- .../Razor/DefaultAbpCompiledViewProvider.cs | 5 ++ .../Razor/RazorTemplateRenderingEngine.cs | 2 +- .../Scriban/ScribanTemplateRenderingEngine.cs | 2 +- .../AbpCompiledViewProviderOptions_Tests.cs | 2 +- .../RazorTemplateContentFileProvider_Tests.cs | 19 +++++ ...cribanTemplateContentFileProvider_Tests.cs | 19 +++++ .../TextTemplating/TemplateDefinitionTests.cs | 17 ++-- ...lizedTemplateContentReaderFactory_Tests.cs | 2 +- .../TemplateContentFileProvider_Tests.cs | 29 +++++++ .../VirtualFileTemplateContributor_Tests.cs | 6 +- 25 files changed, 356 insertions(+), 89 deletions(-) create mode 100644 framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs create mode 100644 framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/RazorTemplateContentFileProvider_Tests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ScribanTemplateContentFileProvider_Tests.cs create mode 100644 framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider_Tests.cs diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs index ba87dfb4ae..43cc829010 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTemplateRenderer.cs @@ -29,7 +29,7 @@ public class AbpTemplateRenderer : ITemplateRenderer, ITransientDependency string cultureName = null, Dictionary globalContext = null) { - var templateDefinition = TemplateDefinitionManager.Get(templateName); + var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName); var renderEngine = templateDefinition.RenderEngine; diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs index 3c98daa22b..28b2e28ad0 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/AbpTextTemplatingOptions.cs @@ -12,10 +12,13 @@ public class AbpTextTemplatingOptions public string DefaultRenderingEngine { get; set; } + public HashSet DeletedTemplates { get; } + public AbpTextTemplatingOptions() { DefinitionProviders = new TypeList(); ContentContributors = new TypeList(); RenderingEngines = new Dictionary(); + DeletedTemplates = new HashSet(); } } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs new file mode 100644 index 0000000000..e275eb39be --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IDynamicTemplateDefinitionStore.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; + +namespace Volo.Abp.TextTemplating; + +public interface IDynamicTemplateDefinitionStore +{ + Task GetAsync([NotNull] string name); + + Task> GetAllAsync(); + + Task GetOrNullAsync(string name); +} diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs new file mode 100644 index 0000000000..d298a42541 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/IStaticTemplateDefinitionStore.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using JetBrains.Annotations; + +namespace Volo.Abp.TextTemplating; + +public interface IStaticTemplateDefinitionStore +{ + Task GetAsync([NotNull] string name); + + Task> GetAllAsync(); + + Task GetOrNullAsync(string name); +} diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs index 31af5d1da5..7234df7c9c 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading.Tasks; using JetBrains.Annotations; namespace Volo.Abp.TextTemplating; @@ -6,11 +7,11 @@ namespace Volo.Abp.TextTemplating; public interface ITemplateDefinitionManager { [NotNull] - TemplateDefinition Get([NotNull] string name); + Task GetAsync([NotNull] string name); [NotNull] - IReadOnlyList GetAll(); + Task> GetAllAsync(); [CanBeNull] - TemplateDefinition GetOrNull(string name); + Task GetOrNullAsync(string name); } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs new file mode 100644 index 0000000000..326b525c0e --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/NullIDynamicTemplateDefinitionStore.cs @@ -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 CachedTemplateResult = Task.FromResult((TemplateDefinition)null); + + private readonly static Task> CachedFeaturesResult = Task.FromResult((IReadOnlyList)Array.Empty().ToImmutableList()); + + public Task GetAsync(string name) + { + return CachedTemplateResult; + } + + public Task> GetAllAsync() + { + return CachedFeaturesResult; + } + + public Task GetOrNullAsync(string name) + { + return CachedTemplateResult; + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs new file mode 100644 index 0000000000..d12db86da8 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/StaticTemplateDefinitionStore.cs @@ -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> TemplateDefinitions { get; } + + protected AbpTextTemplatingOptions Options { get; } + + protected IServiceProvider ServiceProvider { get; } + + public StaticTemplateDefinitionStore(IOptions options, IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + Options = options.Value; + + TemplateDefinitions = new Lazy>(CreateTextTemplateDefinitions, true); + } + + public virtual Task 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> GetAllAsync() + { + return Task.FromResult>(TemplateDefinitions.Value.Values.ToImmutableList()); + } + + public virtual Task GetOrNullAsync(string name) + { + return Task.FromResult(TemplateDefinitions.Value.GetOrDefault(name)); + } + + protected virtual IDictionary CreateTextTemplateDefinitions() + { + var templates = new Dictionary(); + + 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; + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs index 58ffcc491f..64ecd1f4c7 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateContentProvider.cs @@ -26,14 +26,14 @@ public class TemplateContentProvider : ITemplateContentProvider, ITransientDepen _templateDefinitionManager = templateDefinitionManager; } - public virtual Task GetContentOrNullAsync( + public virtual async Task GetContentOrNullAsync( [NotNull] string templateName, [CanBeNull] string cultureName = null, bool tryDefaults = true, bool useCurrentCultureIfCultureNameIsNull = true) { - var template = _templateDefinitionManager.Get(templateName); - return GetContentOrNullAsync(template, cultureName); + var template = await _templateDefinitionManager.GetAsync(templateName); + return await GetContentOrNullAsync(template, cultureName); } public virtual async Task GetContentOrNullAsync( diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs index d028f46702..c6370eec1d 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs @@ -28,7 +28,7 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName public string Layout { get; set; } [CanBeNull] - public Type LocalizationResource { get; set; } + public string LocalizationResourceName { get; set; } public bool IsInlineLocalized { get; set; } @@ -60,14 +60,14 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName public TemplateDefinition( [NotNull] string name, - [CanBeNull] Type localizationResource = null, + [CanBeNull] string localizationResourceName = null, [CanBeNull] ILocalizableString displayName = null, bool isLayout = false, string layout = null, string defaultCultureName = null) { Name = Check.NotNullOrWhiteSpace(name, nameof(name), MaxNameLength); - LocalizationResource = localizationResource; + LocalizationResourceName = localizationResourceName; DisplayName = displayName ?? new FixedLocalizableString(Name); IsLayout = isLayout; Layout = layout; diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs index a282b5e5e2..7e2920e446 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinitionManager.cs @@ -1,85 +1,50 @@ -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.TextTemplating; public class TemplateDefinitionManager : ITemplateDefinitionManager, ISingletonDependency { - protected Lazy> TemplateDefinitions { get; } + protected readonly IStaticTemplateDefinitionStore StaticStore; + protected readonly IDynamicTemplateDefinitionStore DynamicStore; - protected AbpTextTemplatingOptions Options { get; } - - protected IServiceProvider ServiceProvider { get; } - - public TemplateDefinitionManager( - IOptions options, - IServiceProvider serviceProvider) + public TemplateDefinitionManager(IStaticTemplateDefinitionStore staticStore, IDynamicTemplateDefinitionStore dynamicStore) { - ServiceProvider = serviceProvider; - Options = options.Value; - - TemplateDefinitions = - new Lazy>(CreateTextTemplateDefinitions, true); + StaticStore = staticStore; + DynamicStore = dynamicStore; } - public virtual TemplateDefinition Get(string name) + public virtual async Task GetAsync(string name) { - Check.NotNull(name, nameof(name)); - - var template = GetOrNull(name); - - if (template == null) + var permission = await GetOrNullAsync(name); + if (permission == null) { - throw new AbpException("Undefined template: " + name); + throw new AbpException("Undefined Template: " + name); } - return template; + return permission; } - public virtual IReadOnlyList GetAll() + public virtual async Task GetOrNullAsync(string name) { - return TemplateDefinitions.Value.Values.ToImmutableList(); - } + Check.NotNull(name, nameof(name)); - public virtual TemplateDefinition GetOrNull(string name) - { - return TemplateDefinitions.Value.GetOrDefault(name); + return await StaticStore.GetOrNullAsync(name) ?? await DynamicStore.GetOrNullAsync(name); } - protected virtual IDictionary CreateTextTemplateDefinitions() + public virtual async Task> GetAllAsync() { - var templates = new Dictionary(); - - using (var scope = ServiceProvider.CreateScope()) - { - var providers = Options - .DefinitionProviders - .Select(p => scope.ServiceProvider.GetRequiredService(p) as ITemplateDefinitionProvider) - .ToList(); - - var context = new TemplateDefinitionContext(templates); + var staticTemplates = await StaticStore.GetAllAsync(); + var staticTemplateNames = staticTemplates + .Select(p => p.Name) + .ToImmutableHashSet(); - foreach (var provider in providers) - { - provider.PreDefine(context); - } - - foreach (var provider in providers) - { - provider.Define(context); - } - - foreach (var provider in providers) - { - provider.PostDefine(context); - } - } + var dynamicTemplates = await DynamicStore.GetAllAsync(); - return templates; + /* We prefer static Templates over dynamics */ + return staticTemplates.Concat(dynamicTemplates.Where(d => !staticTemplateNames.Contains(d.Name))).ToImmutableList(); } } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs index f496a8fea8..a2c354801d 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateRenderingEngineBase.cs @@ -31,9 +31,9 @@ public abstract class TemplateRenderingEngineBase : ITemplateRenderingEngine protected virtual IStringLocalizer GetLocalizerOrNull(TemplateDefinition templateDefinition) { - if (templateDefinition.LocalizationResource != null) + if (templateDefinition.LocalizationResourceName != null) { - return StringLocalizerFactory.Create(templateDefinition.LocalizationResource); + return StringLocalizerFactory.CreateByResourceName(templateDefinition.LocalizationResourceName); } return StringLocalizerFactory.CreateDefaultOrNull(); diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs index 0ae297a136..27e400c082 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/FileInfoLocalizedTemplateContentReader.cs @@ -5,10 +5,12 @@ namespace Volo.Abp.TextTemplating.VirtualFiles; public class FileInfoLocalizedTemplateContentReader : ILocalizedTemplateContentReader { + private IFileInfo _fileInfo; private string _content; public async Task ReadContentsAsync(IFileInfo fileInfo) { + _fileInfo = fileInfo; _content = await fileInfo.ReadAsStringAsync(); } @@ -21,4 +23,13 @@ public class FileInfoLocalizedTemplateContentReader : ILocalizedTemplateContentR return null; } + + public TemplateContentFileInfo GetFile() + { + return new TemplateContentFileInfo() + { + FileName = _fileInfo.Name, + FileContent = _content + }; + } } diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs new file mode 100644 index 0000000000..5469700432 --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileInfo.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.TextTemplating.VirtualFiles; + +public class TemplateContentFileInfo +{ + public string FileName { get; set; } + + public string FileContent { get; set; } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider.cs new file mode 100644 index 0000000000..0b049b07ab --- /dev/null +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/TemplateContentFileProvider.cs @@ -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> GetFilesAsync(TemplateDefinition templateDefinition) + { + var files = new List(); + + 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; + } +} diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs index 6ff24e4801..828978b1d2 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/VirtualFiles/VirtualFolderLocalizedTemplateContentReader.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.FileProviders; using Volo.Abp.VirtualFileSystem; @@ -8,7 +9,7 @@ namespace Volo.Abp.TextTemplating.VirtualFiles; public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateContentReader { - private Dictionary _dictionary; + private Dictionary _dictionary; private readonly string[] _fileExtension; public VirtualFolderLocalizedTemplateContentReader(string[] fileExtension) @@ -20,7 +21,7 @@ public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateCon IVirtualFileProvider virtualFileProvider, string virtualPath) { - _dictionary = new Dictionary(); + _dictionary = new Dictionary(); var directoryContents = virtualFileProvider.GetDirectoryContents(virtualPath); if (!directoryContents.Exists) @@ -35,7 +36,11 @@ public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateCon continue; } - _dictionary.Add(file.Name.RemovePostFix(_fileExtension), await file.ReadAsStringAsync()); + _dictionary.Add(file.Name.RemovePostFix(_fileExtension), new TemplateContentFileInfo() + { + FileName = file.Name, + FileContent = await file.ReadAsStringAsync() + }); } } @@ -46,6 +51,11 @@ public class VirtualFolderLocalizedTemplateContentReader : ILocalizedTemplateCon return null; } - return _dictionary.GetOrDefault(cultureName); + return _dictionary.GetOrDefault(cultureName)?.FileContent; + } + + public List GetFiles() + { + return _dictionary.Values.ToList(); } } diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs index 10312e1513..109547ada5 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/DefaultAbpCompiledViewProvider.cs @@ -45,6 +45,11 @@ public class DefaultAbpCompiledViewProvider : IAbpCompiledViewProvider, ITransie } var templateContent = await _templateContentProvider.GetContentOrNullAsync(templateDefinition); + if (templateContent == null) + { + throw new AbpException($"Razor template content of {templateDefinition.Name} is null!"); + } + return CachedAssembles.GetOrAdd((templateDefinition.Name + templateContent).ToMd5(), await CreateAssembly(templateContent)); } diff --git a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs index 582ebaf907..86298f2daf 100644 --- a/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs +++ b/framework/src/Volo.Abp.TextTemplating.Razor/Volo/Abp/TextTemplating/Razor/RazorTemplateRenderingEngine.cs @@ -74,7 +74,7 @@ public class RazorTemplateRenderingEngine : TemplateRenderingEngineBase, ITransi Dictionary globalContext, object model = null) { - var templateDefinition = TemplateDefinitionManager.Get(templateName); + var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName); var renderedContent = await RenderSingleTemplateAsync( templateDefinition, diff --git a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs index 4612ec04df..a4da669893 100644 --- a/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs +++ b/framework/src/Volo.Abp.TextTemplating.Scriban/Volo/Abp/TextTemplating/Scriban/ScribanTemplateRenderingEngine.cs @@ -61,7 +61,7 @@ public class ScribanTemplateRenderingEngine : TemplateRenderingEngineBase, ITran Dictionary globalContext, object model = null) { - var templateDefinition = TemplateDefinitionManager.Get(templateName); + var templateDefinition = await TemplateDefinitionManager.GetAsync(templateName); var renderedContent = await RenderSingleTemplateAsync( templateDefinition, diff --git a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs index 6a0edcb3f5..fada3effe7 100644 --- a/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Razor.Tests/Volo/Abp/TextTemplating/Razor/AbpCompiledViewProviderOptions_Tests.cs @@ -38,7 +38,7 @@ public class AbpCompiledViewProviderOptions_Tests : TemplateDefinitionTests +{ + [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!")); + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ScribanTemplateContentFileProvider_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ScribanTemplateContentFileProvider_Tests.cs new file mode 100644 index 0000000000..674173313c --- /dev/null +++ b/framework/test/Volo.Abp.TextTemplating.Scriban.Tests/Volo/Abp/TextTemplating/Scriban/SampleTemplates/ScribanTemplateContentFileProvider_Tests.cs @@ -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 +{ + [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!")); + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs index 036080cc26..02ce27d2b7 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TemplateDefinitionTests.cs @@ -1,4 +1,5 @@ -using Shouldly; +using System.Threading.Tasks; +using Shouldly; using Volo.Abp.Modularity; using Xunit; @@ -15,28 +16,28 @@ public abstract class TemplateDefinitionTests : AbpTextTemplatin } [Fact] - public void Should_Retrieve_Template_Definition_By_Name() + public async Task Should_Retrieve_Template_Definition_By_Name() { - var welcomeEmailTemplate = TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail); + var welcomeEmailTemplate = await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail); welcomeEmailTemplate.Name.ShouldBe(TestTemplates.WelcomeEmail); welcomeEmailTemplate.IsInlineLocalized.ShouldBeFalse(); - var forgotPasswordEmailTemplate = TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail); + var forgotPasswordEmailTemplate = await TemplateDefinitionManager.GetAsync(TestTemplates.ForgotPasswordEmail); forgotPasswordEmailTemplate.Name.ShouldBe(TestTemplates.ForgotPasswordEmail); forgotPasswordEmailTemplate.IsInlineLocalized.ShouldBeTrue(); } [Fact] - public void Should_Get_Null_If_Template_Not_Found() + public async Task Should_Get_Null_If_Template_Not_Found() { - var definition = TemplateDefinitionManager.GetOrNull("undefined-template"); + var definition = await TemplateDefinitionManager.GetOrNullAsync("undefined-template"); definition.ShouldBeNull(); } [Fact] - public void Should_Retrieve_All_Template_Definitions() + public async Task Should_Retrieve_All_Template_Definitions() { - var definitions = TemplateDefinitionManager.GetAll(); + var definitions = await TemplateDefinitionManager.GetAllAsync(); definitions.Count.ShouldBeGreaterThan(1); } } diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs index 7ba1850d9c..aee41db4be 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/LocalizedTemplateContentReaderFactory_Tests.cs @@ -24,7 +24,7 @@ public abstract class LocalizedTemplateContentReaderFactory_Tests : AbpTextTemplatingTestBase + where TStartupModule : IAbpModule +{ + protected readonly TemplateContentFileProvider TemplateContentFileProvider; + protected readonly ITemplateDefinitionManager TemplateDefinitionManager; + + protected TemplateContentFileProvider_Tests() + { + TemplateContentFileProvider = GetRequiredService(); + TemplateDefinitionManager = GetRequiredService(); + } + + [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\" }}"); + } +} diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs index 89dc93051c..f2f0cdafef 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/VirtualFiles/VirtualFileTemplateContributor_Tests.cs @@ -24,13 +24,13 @@ public abstract class VirtualFileTemplateContributor_Tests : Abp public async Task Should_Get_Localized_Content_By_Culture() { (await VirtualFileTemplateContentContributor.GetOrNullAsync( - new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail), + new TemplateContentContributorContext(await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail), ServiceProvider, "en"))) .ShouldBe(WelcomeEmailEnglishContent); (await VirtualFileTemplateContentContributor.GetOrNullAsync( - new TemplateContentContributorContext(TemplateDefinitionManager.Get(TestTemplates.WelcomeEmail), + new TemplateContentContributorContext(await TemplateDefinitionManager.GetAsync(TestTemplates.WelcomeEmail), ServiceProvider, "tr"))) .ShouldBe(WelcomeEmailTurkishContent); @@ -41,7 +41,7 @@ public abstract class VirtualFileTemplateContributor_Tests : Abp { (await VirtualFileTemplateContentContributor.GetOrNullAsync( new TemplateContentContributorContext( - TemplateDefinitionManager.Get(TestTemplates.ForgotPasswordEmail), + await TemplateDefinitionManager.GetAsync(TestTemplates.ForgotPasswordEmail), ServiceProvider, null))) .ShouldBe(ForgotPasswordEmailEnglishContent); From c50cc1ff5f667a5e691d84aa8870430fc05bf9dd Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 7 Jun 2023 17:36:13 +0800 Subject: [PATCH 02/47] Fix unit test. --- .../TextTemplating/TestTemplateDefinitionProvider.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs index 30712c11e0..d0f0e8e0e5 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs @@ -1,4 +1,6 @@ -using Volo.Abp.TextTemplating.Localization; +using JetBrains.Annotations; +using Volo.Abp.Localization; +using Volo.Abp.TextTemplating.Localization; using Volo.Abp.TextTemplating.Razor; using Volo.Abp.TextTemplating.Scriban; @@ -18,7 +20,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.ForgotPasswordEmail, - localizationResource: typeof(TestLocalizationSource), + localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), layout: TestTemplates.TestTemplateLayout1 ) ); @@ -33,7 +35,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.ShowDecimalNumber, - localizationResource: typeof(TestLocalizationSource), + localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), layout: TestTemplates.TestTemplateLayout1 ) ); @@ -41,7 +43,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.HybridTemplateScriban, - localizationResource: typeof(TestLocalizationSource), + localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), layout: null ) .WithVirtualFilePath("/SampleTemplates/TestScribanTemplate.tpl", true) @@ -51,7 +53,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.HybridTemplateRazor, - localizationResource: typeof(TestLocalizationSource), + localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), layout: null ) .WithVirtualFilePath("/SampleTemplates/TestRazorTemplate.cshtml", true) From 4b480108f86f63c454c9c35e90b858df4ffb90c8 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 7 Jun 2023 19:34:13 +0800 Subject: [PATCH 03/47] Update AccountEmailTemplateDefinitionProvider.cs --- .../Templates/AccountEmailTemplateDefinitionProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs index d1e0cb20e6..ef917fcb29 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs +++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs @@ -14,7 +14,7 @@ public class AccountEmailTemplateDefinitionProvider : TemplateDefinitionProvider AccountEmailTemplates.PasswordResetLink, displayName: LocalizableString.Create($"TextTemplate:{AccountEmailTemplates.PasswordResetLink}"), layout: StandardEmailTemplates.Layout, - localizationResource: typeof(AccountResource) + localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(AccountResource)) ).WithVirtualFilePath("/Volo/Abp/Account/Emailing/Templates/PasswordResetLink.tpl", true) ); } From a8130614e5ed8ce3b9b581794236dcb109c8a9cf Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 7 Jun 2023 20:51:55 +0800 Subject: [PATCH 04/47] Add another constructor to `TemplateDefinition`. --- .../Volo/Abp/TextTemplating/TemplateDefinition.cs | 12 ++++++++++++ .../TextTemplating/TestTemplateDefinitionProvider.cs | 12 +++++------- .../AccountEmailTemplateDefinitionProvider.cs | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs index c6370eec1d..fbe8afdfd7 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs @@ -58,6 +58,18 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName [NotNull] public Dictionary Properties { get; } + public TemplateDefinition( + [NotNull] string name, + [CanBeNull] Type localizationResource, + [CanBeNull] ILocalizableString displayName = null, + bool isLayout = false, + string layout = null, + string defaultCultureName = null) + : this(name, LocalizationResourceNameAttribute.GetName(localizationResource), displayName, isLayout, layout, defaultCultureName) + { + + } + public TemplateDefinition( [NotNull] string name, [CanBeNull] string localizationResourceName = null, diff --git a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs index d0f0e8e0e5..30712c11e0 100644 --- a/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs +++ b/framework/test/Volo.Abp.TextTemplating.Tests/Volo/Abp/TextTemplating/TestTemplateDefinitionProvider.cs @@ -1,6 +1,4 @@ -using JetBrains.Annotations; -using Volo.Abp.Localization; -using Volo.Abp.TextTemplating.Localization; +using Volo.Abp.TextTemplating.Localization; using Volo.Abp.TextTemplating.Razor; using Volo.Abp.TextTemplating.Scriban; @@ -20,7 +18,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.ForgotPasswordEmail, - localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), + localizationResource: typeof(TestLocalizationSource), layout: TestTemplates.TestTemplateLayout1 ) ); @@ -35,7 +33,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.ShowDecimalNumber, - localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), + localizationResource: typeof(TestLocalizationSource), layout: TestTemplates.TestTemplateLayout1 ) ); @@ -43,7 +41,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.HybridTemplateScriban, - localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), + localizationResource: typeof(TestLocalizationSource), layout: null ) .WithVirtualFilePath("/SampleTemplates/TestScribanTemplate.tpl", true) @@ -53,7 +51,7 @@ public class TestTemplateDefinitionProvider : TemplateDefinitionProvider context.Add( new TemplateDefinition( TestTemplates.HybridTemplateRazor, - localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(TestLocalizationSource)), + localizationResource: typeof(TestLocalizationSource), layout: null ) .WithVirtualFilePath("/SampleTemplates/TestRazorTemplate.cshtml", true) diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs index ef917fcb29..d1e0cb20e6 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs +++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/Emailing/Templates/AccountEmailTemplateDefinitionProvider.cs @@ -14,7 +14,7 @@ public class AccountEmailTemplateDefinitionProvider : TemplateDefinitionProvider AccountEmailTemplates.PasswordResetLink, displayName: LocalizableString.Create($"TextTemplate:{AccountEmailTemplates.PasswordResetLink}"), layout: StandardEmailTemplates.Layout, - localizationResourceName: LocalizationResourceNameAttribute.GetName(typeof(AccountResource)) + localizationResource: typeof(AccountResource) ).WithVirtualFilePath("/Volo/Abp/Account/Emailing/Templates/PasswordResetLink.tpl", true) ); } From 66cfd1eba01a3e0b28ba2e5906346efad647806c Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 8 Jun 2023 09:37:40 +0800 Subject: [PATCH 05/47] Update TemplateDefinition.cs --- .../Volo/Abp/TextTemplating/TemplateDefinition.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs index fbe8afdfd7..64aeba815e 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/TemplateDefinition.cs @@ -60,7 +60,7 @@ public class TemplateDefinition : IHasNameWithLocalizableDisplayName public TemplateDefinition( [NotNull] string name, - [CanBeNull] Type localizationResource, + [NotNull] Type localizationResource, [CanBeNull] ILocalizableString displayName = null, bool isLayout = false, string layout = null, From 222159378f796aa23f4faa6cad4a740fabd76adc Mon Sep 17 00:00:00 2001 From: Masum ULU Date: Mon, 12 Jun 2023 10:06:26 +0300 Subject: [PATCH 06/47] Password directive created --- .../packages/core/src/lib/directives/index.ts | 1 + .../lib/directives/show-password.directive.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts diff --git a/npm/ng-packs/packages/core/src/lib/directives/index.ts b/npm/ng-packs/packages/core/src/lib/directives/index.ts index 8f05e2daae..a2f5d8e4fe 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/index.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/index.ts @@ -6,3 +6,4 @@ export * from './init.directive'; export * from './permission.directive'; export * from './replaceable-template.directive'; export * from './stop-propagation.directive'; +export * from './show-password.directive'; diff --git a/npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts new file mode 100644 index 0000000000..03dc44f6a5 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/directives/show-password.directive.ts @@ -0,0 +1,16 @@ +import { Directive, ElementRef, Input, inject } from '@angular/core'; + +@Directive({ + standalone: true, + selector: '[abpShowPassword]', +}) +export class ShowPasswordDirective { + protected readonly elementRef = inject(ElementRef); + + @Input() set abpShowPassword(visible: boolean) { + const element = this.elementRef.nativeElement as HTMLInputElement; + if (!element) return; + + element.type = visible ? 'text' : 'password'; + } +} From bf70b56375b15dbae00491391104d1042ed3fa13 Mon Sep 17 00:00:00 2001 From: Masum ULU Date: Mon, 12 Jun 2023 10:22:06 +0300 Subject: [PATCH 07/47] fix wrong imports for account layout --- npm/ng-packs/apps/dev-app/src/app/app.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/apps/dev-app/src/app/app.module.ts b/npm/ng-packs/apps/dev-app/src/app/app.module.ts index ac56d2736e..7e903dff0d 100644 --- a/npm/ng-packs/apps/dev-app/src/app/app.module.ts +++ b/npm/ng-packs/apps/dev-app/src/app/app.module.ts @@ -12,7 +12,7 @@ import { SettingManagementConfigModule } from '@abp/ng.setting-management/config import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config'; import { FeatureManagementModule } from '@abp/ng.feature-management'; import { AccountConfigModule } from '@abp/ng.account/config'; -import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account/account-layout'; +import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account'; import { environment } from '../environments/environment'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; From a0df51dd23a0bdb77dd9385c951d7c71ccf2f1b7 Mon Sep 17 00:00:00 2001 From: Masum ULU Date: Mon, 12 Jun 2023 14:35:57 +0300 Subject: [PATCH 08/47] caps-lock directive added --- .../src/lib/directives/caps-lock.directive.ts | 30 +++++++++++++++++++ .../packages/core/src/lib/directives/index.ts | 1 + 2 files changed, 31 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts diff --git a/npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts new file mode 100644 index 0000000000..7da2eb32cf --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts @@ -0,0 +1,30 @@ +import { Directive, EventEmitter, HostListener, Output } from '@angular/core'; + +@Directive({ + standalone: true, + selector: '[abpCapsLock]', +}) +export class TrackCapsLockDirective { + @Output('abpCapsLock') capsLock = new EventEmitter(); + + @HostListener('window:keydown', ['$event']) + onKeyDown(event: KeyboardEvent): void { + this.capsLock.emit(this.capS(event)); + } + @HostListener('window:keyup', ['$event']) + onKeyUp(event: KeyboardEvent): void { + this.capsLock.emit(this.capS(event)); + } + + capS(e) { + var s = String.fromCharCode(e.which); + if ( + (s.toUpperCase() === s && s.toLowerCase() !== s && e.shiftKey) || + (s.toUpperCase() !== s && s.toLowerCase() === s && e.shiftKey) || + e.getModifierState('CapsLock') + ) { + return true; + } + return false; + } +} diff --git a/npm/ng-packs/packages/core/src/lib/directives/index.ts b/npm/ng-packs/packages/core/src/lib/directives/index.ts index a2f5d8e4fe..d5d6e22c31 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/index.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/index.ts @@ -7,3 +7,4 @@ export * from './permission.directive'; export * from './replaceable-template.directive'; export * from './stop-propagation.directive'; export * from './show-password.directive'; +export * from './caps-lock.directive'; From a5dfdb4c50bf84a4954b3b2ce0ea4e89ddba4fbc Mon Sep 17 00:00:00 2001 From: Masum ULU Date: Mon, 12 Jun 2023 14:37:21 +0300 Subject: [PATCH 09/47] fix method name --- .../packages/core/src/lib/directives/caps-lock.directive.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts b/npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts index 7da2eb32cf..0194bb9d3e 100644 --- a/npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts +++ b/npm/ng-packs/packages/core/src/lib/directives/caps-lock.directive.ts @@ -9,14 +9,14 @@ export class TrackCapsLockDirective { @HostListener('window:keydown', ['$event']) onKeyDown(event: KeyboardEvent): void { - this.capsLock.emit(this.capS(event)); + this.capsLock.emit(this.isCapsLockOpen(event)); } @HostListener('window:keyup', ['$event']) onKeyUp(event: KeyboardEvent): void { - this.capsLock.emit(this.capS(event)); + this.capsLock.emit(this.isCapsLockOpen(event)); } - capS(e) { + isCapsLockOpen(e): boolean { var s = String.fromCharCode(e.which); if ( (s.toUpperCase() === s && s.toLowerCase() !== s && e.shiftKey) || From 121baefe48d4a9c94bd1d26b7694309f0835938f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Tue, 13 Jun 2023 09:18:27 +0300 Subject: [PATCH 10/47] Update annotations --- .../Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs index 7234df7c9c..fa20673cea 100644 --- a/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs +++ b/framework/src/Volo.Abp.TextTemplating.Core/Volo/Abp/TextTemplating/ITemplateDefinitionManager.cs @@ -6,12 +6,12 @@ namespace Volo.Abp.TextTemplating; public interface ITemplateDefinitionManager { - [NotNull] + [ItemNotNull] Task GetAsync([NotNull] string name); - [NotNull] + [ItemNotNull] Task> GetAllAsync(); - [CanBeNull] + [ItemCanBeNull] Task GetOrNullAsync(string name); } From e686f74f8b8ff86c3de4f5056d79787f40e52802 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 13 Jun 2023 15:30:07 +0800 Subject: [PATCH 11/47] Create Abp-7_4.md --- .../Migration-Guides/docs/en/Migration-Guides/Abp-7_4.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/en/Migration-Guides/docs/en/Migration-Guides/Abp-7_4.md diff --git a/docs/en/Migration-Guides/docs/en/Migration-Guides/Abp-7_4.md b/docs/en/Migration-Guides/docs/en/Migration-Guides/Abp-7_4.md new file mode 100644 index 0000000000..5ec8eb6c65 --- /dev/null +++ b/docs/en/Migration-Guides/docs/en/Migration-Guides/Abp-7_4.md @@ -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)`. + From 78eb588712c71e0fac81b6b7dcb7d5068abfaf2b Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 13 Jun 2023 19:33:40 +0800 Subject: [PATCH 12/47] Incorrect filtering for Booleans has been fixed in the IdentityUserRepository. Resolve #16818 https://github.com/abpframework/abp/pull/15687 --- .../EntityFrameworkCore/EfCoreIdentityUserRepository.cs | 8 ++++---- .../Abp/Identity/MongoDB/MongoIdentityUserRepository.cs | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs index 60abbb3054..2dc1963505 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EfCoreIdentityUserRepository.cs @@ -252,10 +252,10 @@ public class EfCoreIdentityUserRepository : EfCoreRepository x.Email == emailAddress) .WhereIf(!string.IsNullOrWhiteSpace(name), x => x.Name == name) .WhereIf(!string.IsNullOrWhiteSpace(surname), x => x.Surname == surname) - .WhereIf(isLockedOut.HasValue, x => x.LockoutEnabled && x.LockoutEnd.Value.CompareTo(DateTime.UtcNow) > 0) - .WhereIf(notActive.HasValue, x => !x.IsActive) - .WhereIf(emailConfirmed.HasValue, x => x.EmailConfirmed) - .WhereIf(isExternal.HasValue, x => x.IsExternal) + .WhereIf(isLockedOut.HasValue, x => (x.LockoutEnabled && x.LockoutEnd.HasValue && x.LockoutEnd.Value.CompareTo(DateTime.UtcNow) > 0) == isLockedOut.Value) + .WhereIf(notActive.HasValue, x => x.IsActive == !notActive.Value) + .WhereIf(emailConfirmed.HasValue, x => x.EmailConfirmed == emailConfirmed.Value) + .WhereIf(isExternal.HasValue, x => x.IsExternal == isExternal.Value) .WhereIf(maxCreationTime != null, p => p.CreationTime <= maxCreationTime) .WhereIf(minCreationTime != null, p => p.CreationTime >= minCreationTime) .WhereIf(maxModifitionTime != null, p => p.LastModificationTime <= maxModifitionTime) diff --git a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs index ae805d9a03..552e22afbe 100644 --- a/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs +++ b/modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentityUserRepository.cs @@ -257,10 +257,11 @@ public class MongoIdentityUserRepository : MongoDbRepository>(!string.IsNullOrWhiteSpace(emailAddress), x => x.Email == emailAddress) .WhereIf>(!string.IsNullOrWhiteSpace(name), x => x.Name == name) .WhereIf>(!string.IsNullOrWhiteSpace(surname), x => x.Surname == surname) - .WhereIf>(isLockedOut.HasValue, x => x.LockoutEnabled && x.LockoutEnd > DateTimeOffset.UtcNow) - .WhereIf>(notActive.HasValue, x => !x.IsActive) - .WhereIf>(emailConfirmed.HasValue, x => x.EmailConfirmed) - .WhereIf>(isExternal.HasValue, x => x.IsExternal) + .WhereIf>(isLockedOut.HasValue && isLockedOut.Value, x => x.LockoutEnabled && x.LockoutEnd != null && x.LockoutEnd > DateTimeOffset.UtcNow) + .WhereIf>(isLockedOut.HasValue && !isLockedOut.Value, x => !(x.LockoutEnabled && x.LockoutEnd != null && x.LockoutEnd > DateTimeOffset.UtcNow)) + .WhereIf>(notActive.HasValue, x => x.IsActive == !notActive.Value) + .WhereIf>(emailConfirmed.HasValue, x => x.EmailConfirmed == emailConfirmed.Value) + .WhereIf>(isExternal.HasValue, x => x.IsExternal == isExternal.Value) .WhereIf>(maxCreationTime != null, p => p.CreationTime <= maxCreationTime) .WhereIf>(minCreationTime != null, p => p.CreationTime >= minCreationTime) .WhereIf>(maxModifitionTime != null, p => p.LastModificationTime <= maxModifitionTime) From 42e68e1db5a87d66c723b8d644ecfecd82c0266f Mon Sep 17 00:00:00 2001 From: Mahmut Gundogdu Date: Tue, 13 Jun 2023 15:42:04 +0300 Subject: [PATCH 13/47] Limit forms on settings --- .../email-setting-group/email-setting-group.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html b/npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html index 1baa5c5ff4..03aeb21708 100644 --- a/npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html +++ b/npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.html @@ -2,7 +2,7 @@
-
+