Browse Source

Delete email template system and use the text template system.

pull/3792/head
Halil İbrahim Kalkan 6 years ago
parent
commit
8fb41d9e43
  1. 5
      framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj
  2. 50
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs
  3. 18
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/AbpEmailTemplateOptions.cs
  4. 24
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/DefaultEmailTemplateProvider.cs
  5. 2
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Layout/en.tpl
  6. 42
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplate.cs
  7. 22
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateContributorList.cs
  8. 36
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinition.cs
  9. 38
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionContext.cs
  10. 22
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionDictionary.cs
  11. 74
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionManager.cs
  12. 9
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionProvider.cs
  13. 18
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateInitializationContext.cs
  14. 121
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProvider.cs
  15. 9
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateContributor.cs
  16. 9
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateDefinitionContext.cs
  17. 15
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateDefinitionManager.cs
  18. 7
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateDefinitionProvider.cs
  19. 11
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateProvider.cs
  20. 9
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/ITemplateRender.cs
  21. 15
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/TemplateRender.cs
  22. 19
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/VirtualFiles/EmailTemplateDefinitionExtensions.cs
  23. 68
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/VirtualFiles/MultipleVirtualFilesEmailTemplateContributor.cs
  24. 34
      framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/VirtualFiles/SingleVirtualFileEmailTemplateContributor.cs
  25. 18
      framework/src/Volo.Abp.Localization/Volo/Abp/Localization/TemplateLocalizer.cs
  26. 5
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentProvider.cs
  27. 16
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentProvider.cs
  28. 5
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinition.cs
  29. 47
      framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateRenderer.cs
  30. 7
      framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj
  31. 10
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs
  32. 65
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateRender_Tests.cs
  33. 54
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs
  34. 10
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/AbpEmailingTestResource.cs
  35. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json
  36. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json
  37. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/pl.json
  38. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/pt-BR.json
  39. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/tr.json
  40. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/vi.json
  41. 6
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json
  42. 24
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestEmailTemplateProvider.cs
  43. 4
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template1/en.tpl
  44. 4
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template1/tr.tpl
  45. 4
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template2/en.tpl
  46. 1
      framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template3/Template.tpl
  47. 63
      framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TemplateLocalizer_Tests.cs

5
framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj

@ -24,14 +24,11 @@
<EmbeddedResource Include="Volo\Abp\Emailing\Localization\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Scriban" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.BackgroundJobs.Abstractions\Volo.Abp.BackgroundJobs.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
<ProjectReference Include="..\Volo.Abp.Settings\Volo.Abp.Settings.csproj" />
<ProjectReference Include="..\Volo.Abp.TextTemplating\Volo.Abp.TextTemplating.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
</ItemGroup>

50
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.BackgroundJobs;
using Volo.Abp.Emailing.Localization;
using Volo.Abp.Emailing.Templates;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.Settings;
using Volo.Abp.TextTemplating;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Emailing
@ -15,15 +12,11 @@ namespace Volo.Abp.Emailing
typeof(AbpSettingsModule),
typeof(AbpVirtualFileSystemModule),
typeof(AbpBackgroundJobsAbstractionsModule),
typeof(AbpLocalizationModule)
typeof(AbpLocalizationModule),
typeof(AbpTextTemplatingModule)
)]
public class AbpEmailingModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
AutoAddDefinitionProviders(context.Services);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
@ -43,40 +36,5 @@ namespace Volo.Abp.Emailing
options.AddJob<BackgroundEmailSendingJob>();
});
}
private static void AutoAddDefinitionProviders(IServiceCollection services)
{
var definitionProviders = new List<Type>();
services.OnRegistred(context =>
{
if (typeof(IEmailTemplateDefinitionProvider).IsAssignableFrom(context.ImplementationType))
{
definitionProviders.Add(context.ImplementationType);
}
});
services.Configure<AbpEmailTemplateOptions>(options =>
{
options.DefinitionProviders.AddIfNotContains(definitionProviders);
});
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
using (var scope = context.ServiceProvider.CreateScope())
{
var emailTemplateDefinitionManager =
scope.ServiceProvider.GetRequiredService<IEmailTemplateDefinitionManager>();
foreach (var templateDefinition in emailTemplateDefinitionManager.GetAll())
{
foreach (var contributor in templateDefinition.Contributors)
{
contributor.Initialize(new EmailTemplateInitializationContext(templateDefinition, scope.ServiceProvider));
}
}
}
}
}
}

18
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/AbpEmailTemplateOptions.cs

@ -1,18 +0,0 @@
using Volo.Abp.Collections;
namespace Volo.Abp.Emailing.Templates
{
public class AbpEmailTemplateOptions
{
public string DefaultLayout { get; set; }
public ITypeList<IEmailTemplateDefinitionProvider> DefinitionProviders { get; }
public AbpEmailTemplateOptions()
{
DefaultLayout = StandardEmailTemplates.DefaultLayout;
DefinitionProviders = new TypeList<IEmailTemplateDefinitionProvider>();
}
}
}

24
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/DefaultEmailTemplateProvider.cs

@ -1,16 +1,26 @@
using Volo.Abp.Emailing.Templates.VirtualFiles;
using Volo.Abp.TextTemplating;
namespace Volo.Abp.Emailing.Templates
{
public class DefaultEmailTemplateProvider : EmailTemplateDefinitionProvider
public class DefaultEmailTemplateProvider : TemplateDefinitionProvider
{
public override void Define(IEmailTemplateDefinitionContext context)
public override void Define(ITemplateDefinitionContext context)
{
context.Add(new EmailTemplateDefinition(StandardEmailTemplates.DefaultLayout, defaultCultureName: "en", isLayout: true, layout: null)
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Layout"));
context.Add(
new TemplateDefinition(
StandardEmailTemplates.DefaultLayout,
defaultCultureName: "en",
isLayout: true,
layout: null
).AddVirtualFiles("/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Layout")
);
context.Add(new EmailTemplateDefinition(StandardEmailTemplates.SimpleMessage, defaultCultureName: "en")
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Message"));
context.Add(
new TemplateDefinition(
StandardEmailTemplates.SimpleMessage,
defaultCultureName: "en"
).AddVirtualFiles("/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Message")
);
}
}
}

2
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/DefaultEmailTemplates/Layout/en.tpl

@ -4,6 +4,6 @@
<meta charset="utf-8" />
</head>
<body>
{{#content}}
{{content}}
</body>
</html>

42
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplate.cs

@ -1,42 +0,0 @@
using System.Text;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplate
{
public EmailTemplateDefinition Definition { get; }
public string Content => ContentBuilder.ToString();
protected StringBuilder ContentBuilder { get; set; }
public EmailTemplate(string content, EmailTemplateDefinition definition)
{
ContentBuilder = new StringBuilder(content);
Definition = definition;
}
public virtual void SetLayout(EmailTemplate layoutTemplate)
{
if (!layoutTemplate.Definition.IsLayout)
{
throw new AbpException($"Given template is not a layout template: {layoutTemplate.Definition.Name}");
}
var newStrBuilder = new StringBuilder(layoutTemplate.Content);
newStrBuilder.Replace("{{#content}}", ContentBuilder.ToString());
ContentBuilder = newStrBuilder;
}
public virtual void SetContent(string content)
{
ContentBuilder = new StringBuilder(content);
}
public virtual void Replace(string name, string value)
{
ContentBuilder.Replace("{{" + name + "}}", value);
}
}
}

22
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateContributorList.cs

@ -1,22 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplateContributorList : List<IEmailTemplateContributor>
{
public string GetOrNull(string cultureName)
{
foreach (var contributor in this.AsQueryable().Reverse())
{
var templateString = contributor.GetOrNull(cultureName);
if (templateString != null)
{
return templateString;
}
}
return null;
}
}
}

36
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinition.cs

@ -1,36 +0,0 @@
using System;
using JetBrains.Annotations;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplateDefinition
{
public const string DefaultLayoutPlaceHolder = "_";
public string Name { get; }
public bool IsLayout { get; }
public string Layout { get; set; }
public Type LocalizationResource { get; set; }
public EmailTemplateContributorList Contributors { get; }
public string DefaultCultureName { get; }
public bool SingleTemplateFile { get; }
public EmailTemplateDefinition([NotNull] string name, Type localizationResource = null, bool isLayout = false,
string layout = DefaultLayoutPlaceHolder, string defaultCultureName = null, bool singleTemplateFile = false)
{
Name = Check.NotNullOrWhiteSpace(name, nameof(name));
LocalizationResource = localizationResource;
Contributors = new EmailTemplateContributorList();
IsLayout = isLayout;
Layout = layout;
DefaultCultureName = defaultCultureName;
SingleTemplateFile = singleTemplateFile;
}
}
}

38
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionContext.cs

@ -1,38 +0,0 @@
using System.Collections.Generic;
using System.Collections.Immutable;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplateDefinitionContext : IEmailTemplateDefinitionContext
{
protected Dictionary<string, EmailTemplateDefinition> EmailTemplates { get; }
public EmailTemplateDefinitionContext(Dictionary<string, EmailTemplateDefinition> emailTemplates)
{
EmailTemplates = emailTemplates;
}
public virtual EmailTemplateDefinition GetOrNull(string name)
{
return EmailTemplates.GetOrDefault(name);
}
public virtual IReadOnlyList<EmailTemplateDefinition> GetAll()
{
return EmailTemplates.Values.ToImmutableList();
}
public virtual void Add(params EmailTemplateDefinition[] definitions)
{
if (definitions.IsNullOrEmpty())
{
return;
}
foreach (var definition in definitions)
{
EmailTemplates[definition.Name] = definition;
}
}
}
}

22
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionDictionary.cs

@ -1,22 +0,0 @@
using System.Collections.Generic;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplateDefinitionDictionary : Dictionary<string, EmailTemplateDefinition>
{
public EmailTemplateDefinitionDictionary Add(EmailTemplateDefinition emailTemplateDefinition)
{
if (ContainsKey(emailTemplateDefinition.Name))
{
throw new AbpException(
"There is already an email template definition with given name: " +
emailTemplateDefinition.Name
);
}
this[emailTemplateDefinition.Name] = emailTemplateDefinition;
return this;
}
}
}

74
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionManager.cs

@ -1,74 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplateDefinitionManager : IEmailTemplateDefinitionManager, ISingletonDependency
{
protected Lazy<IDictionary<string, EmailTemplateDefinition>> EmailTemplateDefinitions { get; }
protected AbpEmailTemplateOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
public EmailTemplateDefinitionManager(
IOptions<AbpEmailTemplateOptions> options,
IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
Options = options.Value;
EmailTemplateDefinitions =
new Lazy<IDictionary<string, EmailTemplateDefinition>>(CreateEmailTemplateDefinitions, true);
}
public virtual EmailTemplateDefinition Get(string name)
{
Check.NotNull(name, nameof(name));
var template = GetOrNull(name);
if (template == null)
{
throw new AbpException("Undefined template: " + name);
}
return template;
}
public virtual IReadOnlyList<EmailTemplateDefinition> GetAll()
{
return EmailTemplateDefinitions.Value.Values.ToImmutableList();
}
public virtual EmailTemplateDefinition GetOrNull(string name)
{
return EmailTemplateDefinitions.Value.GetOrDefault(name);
}
protected virtual IDictionary<string, EmailTemplateDefinition> CreateEmailTemplateDefinitions()
{
var templates = new Dictionary<string, EmailTemplateDefinition>();
using (var scope = ServiceProvider.CreateScope())
{
var providers = Options
.DefinitionProviders
.Select(p => scope.ServiceProvider.GetRequiredService(p) as IEmailTemplateDefinitionProvider)
.ToList();
foreach (var provider in providers)
{
provider.Define(new EmailTemplateDefinitionContext(templates));
}
}
return templates;
}
}
}

9
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionProvider.cs

@ -1,9 +0,0 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Emailing.Templates
{
public abstract class EmailTemplateDefinitionProvider : IEmailTemplateDefinitionProvider, ITransientDependency
{
public abstract void Define(IEmailTemplateDefinitionContext context);
}
}

18
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateInitializationContext.cs

@ -1,18 +0,0 @@
using System;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplateInitializationContext
{
public EmailTemplateDefinition EmailTemplateDefinition { get; }
public IServiceProvider ServiceProvider { get; }
public EmailTemplateInitializationContext(EmailTemplateDefinition emailTemplateDefinition,
IServiceProvider serviceProvider)
{
EmailTemplateDefinition = emailTemplateDefinition;
ServiceProvider = serviceProvider;
}
}
}

121
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProvider.cs

@ -1,121 +0,0 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
namespace Volo.Abp.Emailing.Templates
{
public class EmailTemplateProvider : IEmailTemplateProvider, ITransientDependency
{
protected IEmailTemplateDefinitionManager EmailTemplateDefinitionManager;
protected ITemplateLocalizer TemplateLocalizer { get; }
protected AbpEmailTemplateOptions Options { get; }
protected IStringLocalizerFactory StringLocalizerFactory;
public EmailTemplateProvider(IEmailTemplateDefinitionManager emailTemplateDefinitionManager,
ITemplateLocalizer templateLocalizer, IStringLocalizerFactory stringLocalizerFactory,
IOptions<AbpEmailTemplateOptions> options)
{
EmailTemplateDefinitionManager = emailTemplateDefinitionManager;
TemplateLocalizer = templateLocalizer;
StringLocalizerFactory = stringLocalizerFactory;
Options = options.Value;
}
public async Task<EmailTemplate> GetAsync(string name)
{
return await GetAsync(name, CultureInfo.CurrentUICulture.Name);
}
public async Task<EmailTemplate> GetAsync(string name, string cultureName)
{
return await GetInternalAsync(name, cultureName);
}
protected virtual async Task<EmailTemplate> GetInternalAsync(string name, string cultureName)
{
var emailTemplateDefinition = EmailTemplateDefinitionManager.GetOrNull(name);
if (emailTemplateDefinition == null)
{
// TODO: Localized message
throw new AbpException($"email template {name} not definition");
}
var emailTemplateString = emailTemplateDefinition.Contributors.GetOrNull(cultureName);
if (emailTemplateString == null && emailTemplateDefinition.DefaultCultureName != null)
{
emailTemplateString =
emailTemplateDefinition.Contributors.GetOrNull(emailTemplateDefinition.DefaultCultureName);
if (emailTemplateString != null)
{
cultureName = emailTemplateDefinition.DefaultCultureName;
}
}
if (emailTemplateString != null)
{
var emailTemplate = new EmailTemplate(emailTemplateString, emailTemplateDefinition);
await SetLayoutAsync(emailTemplateDefinition, emailTemplate, cultureName);
if (emailTemplateDefinition.SingleTemplateFile)
{
await LocalizeAsync(emailTemplateDefinition, emailTemplate, cultureName);
}
return emailTemplate;
}
// TODO: Localized message
throw new AbpException($"{cultureName} template not exist!");
}
protected virtual async Task SetLayoutAsync(EmailTemplateDefinition emailTemplateDefinition,
EmailTemplate emailTemplate, string cultureName)
{
var layout = emailTemplateDefinition.Layout;
if (layout.IsNullOrWhiteSpace())
{
return;
}
if (layout == EmailTemplateDefinition.DefaultLayoutPlaceHolder)
{
layout = Options.DefaultLayout;
}
var layoutTemplate = await GetInternalAsync(layout, cultureName);
emailTemplate.SetLayout(layoutTemplate);
}
protected virtual Task LocalizeAsync(EmailTemplateDefinition emailTemplateDefinition,
EmailTemplate emailTemplate, string cultureName)
{
if (emailTemplateDefinition.LocalizationResource == null)
{
return Task.CompletedTask;
}
var localizer = StringLocalizerFactory.Create(emailTemplateDefinition.LocalizationResource);
if (cultureName != null)
{
using (CultureHelper.Use(new CultureInfo(cultureName)))
{
emailTemplate.SetContent(TemplateLocalizer.Localize(localizer, emailTemplate.Content));
}
}
else
{
emailTemplate.SetContent(
TemplateLocalizer.Localize(localizer, emailTemplate.Content)
);
}
return Task.CompletedTask;
}
}
}

9
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateContributor.cs

@ -1,9 +0,0 @@
namespace Volo.Abp.Emailing.Templates
{
public interface IEmailTemplateContributor
{
void Initialize(EmailTemplateInitializationContext context);
string GetOrNull(string cultureName);
}
}

9
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateDefinitionContext.cs

@ -1,9 +0,0 @@
namespace Volo.Abp.Emailing.Templates
{
public interface IEmailTemplateDefinitionContext
{
EmailTemplateDefinition GetOrNull(string name);
void Add(params EmailTemplateDefinition[] definitions);
}
}

15
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateDefinitionManager.cs

@ -1,15 +0,0 @@
using System.Collections.Generic;
using JetBrains.Annotations;
namespace Volo.Abp.Emailing.Templates
{
public interface IEmailTemplateDefinitionManager
{
[NotNull]
EmailTemplateDefinition Get([NotNull] string name);
IReadOnlyList<EmailTemplateDefinition> GetAll();
EmailTemplateDefinition GetOrNull(string name);
}
}

7
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateDefinitionProvider.cs

@ -1,7 +0,0 @@
namespace Volo.Abp.Emailing.Templates
{
public interface IEmailTemplateDefinitionProvider
{
void Define(IEmailTemplateDefinitionContext context);
}
}

11
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateProvider.cs

@ -1,11 +0,0 @@
using System.Threading.Tasks;
namespace Volo.Abp.Emailing.Templates
{
public interface IEmailTemplateProvider
{
Task<EmailTemplate> GetAsync(string name);
Task<EmailTemplate> GetAsync(string name, string cultureName);
}
}

9
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/ITemplateRender.cs

@ -1,9 +0,0 @@
using System.Threading.Tasks;
namespace Volo.Abp.Emailing.Templates
{
public interface ITemplateRender
{
Task<string> RenderAsync(string template, object model = null);
}
}

15
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/TemplateRender.cs

@ -1,15 +0,0 @@
using System.Threading.Tasks;
using Scriban;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Emailing.Templates
{
public class TemplateRender : ITemplateRender, ITransientDependency
{
public async Task<string> RenderAsync(string template, object model = null)
{
var scribanTemplate = Template.Parse(template);
return await scribanTemplate.RenderAsync(model);
}
}
}

19
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/VirtualFiles/EmailTemplateDefinitionExtensions.cs

@ -1,19 +0,0 @@
namespace Volo.Abp.Emailing.Templates.VirtualFiles
{
public static class EmailTemplateDefinitionExtensions
{
public static EmailTemplateDefinition AddTemplateVirtualFile(
this EmailTemplateDefinition emailTemplateDefinition, string path)
{
emailTemplateDefinition.Contributors.Add(new SingleVirtualFileEmailTemplateContributor(path));
return emailTemplateDefinition;
}
public static EmailTemplateDefinition AddTemplateVirtualFiles(
this EmailTemplateDefinition emailTemplateDefinition, string path)
{
emailTemplateDefinition.Contributors.Add(new MultipleVirtualFilesEmailTemplateContributor(path));
return emailTemplateDefinition;
}
}
}

68
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/VirtualFiles/MultipleVirtualFilesEmailTemplateContributor.cs

@ -1,68 +0,0 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Emailing.Templates.VirtualFiles
{
public class MultipleVirtualFilesEmailTemplateContributor : IEmailTemplateContributor
{
private readonly string _virtualPath;
private IVirtualFileProvider _virtualFileProvider;
private Dictionary<string, string> _templateDictionary;
private readonly object _syncObj = new object();
public MultipleVirtualFilesEmailTemplateContributor(string virtualPath)
{
_virtualPath = virtualPath;
}
public void Initialize(EmailTemplateInitializationContext context)
{
_virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>();
}
public string GetOrNull(string cultureName)
{
return GetTemplateDictionary().GetOrDefault(cultureName);
}
private Dictionary<string, string> GetTemplateDictionary()
{
var dictionaries = _templateDictionary;
if (dictionaries != null)
{
return dictionaries;
}
lock (_syncObj)
{
dictionaries = _templateDictionary;
if (dictionaries != null)
{
return dictionaries;
}
_templateDictionary = new Dictionary<string, string>();
foreach (var file in _virtualFileProvider.GetDirectoryContents(_virtualPath))
{
if (file.IsDirectory)
{
continue;
}
// TODO: How to normalize file names?
_templateDictionary.Add(file.Name.RemovePostFix(".tpl"), file.ReadAsString());
}
dictionaries = _templateDictionary;
}
return dictionaries;
}
}
}

34
framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/VirtualFiles/SingleVirtualFileEmailTemplateContributor.cs

@ -1,34 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Emailing.Templates.VirtualFiles
{
public class SingleVirtualFileEmailTemplateContributor : IEmailTemplateContributor
{
private readonly string _virtualPath;
private IVirtualFileProvider _virtualFileProvider;
public SingleVirtualFileEmailTemplateContributor(string virtualPath)
{
_virtualPath = virtualPath;
}
public void Initialize(EmailTemplateInitializationContext context)
{
_virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>();
}
public string GetOrNull(string cultureName)
{
var file = _virtualFileProvider.GetFileInfo(_virtualPath);
if (file == null || !file.Exists || file.IsDirectory)
{
return null;
}
return file.ReadAsString();
}
}
}

18
framework/src/Volo.Abp.Localization/Volo/Abp/Localization/TemplateLocalizer.cs

@ -1,18 +0,0 @@
using System.Text.RegularExpressions;
using Microsoft.Extensions.Localization;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Localization
{
public class TemplateLocalizer : ITemplateLocalizer, ITransientDependency
{
public string Localize(IStringLocalizer localizer, string text)
{
return new Regex("\\{\\{#L:.+?\\}\\}")
.Replace(
text,
match => localizer[match.Value.Substring(5, match.Length - 7)]
);
}
}
}

5
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/ITemplateContentProvider.cs

@ -9,5 +9,10 @@ namespace Volo.Abp.TextTemplating
[NotNull] string templateName,
[CanBeNull] string cultureName = null
);
Task<string> GetContentOrNullAsync(
[NotNull] TemplateDefinition templateDefinition,
[CanBeNull] string cultureName = null
);
}
}

16
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateContentProvider.cs

@ -15,15 +15,23 @@ namespace Volo.Abp.TextTemplating
_templateDefinitionManager = templateDefinitionManager;
}
public async Task<string> GetContentOrNullAsync(
public Task<string> GetContentOrNullAsync(
[NotNull] string templateName,
[CanBeNull] string cultureName = null)
{
var template = _templateDefinitionManager.Get(templateName);
return GetContentOrNullAsync(template, cultureName);
}
public async Task<string> GetContentOrNullAsync(
[NotNull] TemplateDefinition templateDefinition,
[CanBeNull] string cultureName = null)
{
Check.NotNull(templateDefinition, nameof(templateDefinition));
foreach (var contributor in template.Contributors)
foreach (var contributor in templateDefinition.Contributors)
{
var templateString = contributor.GetOrNull(cultureName);
var templateString = contributor.GetOrNull(cultureName); //TODO: GetOrNull should be async!
if (templateString != null)
{
return templateString;
@ -31,7 +39,7 @@ namespace Volo.Abp.TextTemplating
}
throw new AbpException(
$"None of the template contributors could get the content for the template '{templateName}'"
$"None of the template contributors could get the content for the template '{templateDefinition.Name}'"
);
}
}

5
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateDefinition.cs

@ -15,7 +15,8 @@ namespace Volo.Abp.TextTemplating
[CanBeNull]
public string Layout { get; set; }
public Type LocalizationResource { get; set; } //TODO: ???
[CanBeNull]
public Type LocalizationResource { get; set; }
public TemplateContributorList Contributors { get; }
@ -24,7 +25,7 @@ namespace Volo.Abp.TextTemplating
public TemplateDefinition(
[NotNull] string name,
Type localizationResource = null,
[CanBeNull] Type localizationResource = null,
bool isLayout = false,
string layout = DefaultLayoutPlaceHolder,
string defaultCultureName = null)

47
framework/src/Volo.Abp.TextTemplating/Volo/Abp/TextTemplating/TemplateRenderer.cs

@ -1,5 +1,7 @@
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using Scriban;
using Volo.Abp.DependencyInjection;
@ -8,11 +10,17 @@ namespace Volo.Abp.TextTemplating
public class TemplateRenderer : ITemplateRenderer, ITransientDependency
{
private readonly ITemplateContentProvider _templateContentProvider;
private readonly ITemplateDefinitionManager _templateDefinitionManager;
private readonly IStringLocalizerFactory _stringLocalizerFactory;
public TemplateRenderer(
ITemplateContentProvider templateContentProvider)
ITemplateContentProvider templateContentProvider,
ITemplateDefinitionManager templateDefinitionManager,
IStringLocalizerFactory stringLocalizerFactory)
{
_templateContentProvider = templateContentProvider;
_templateDefinitionManager = templateDefinitionManager;
_stringLocalizerFactory = stringLocalizerFactory;
}
public virtual async Task<string> RenderAsync(
@ -22,14 +30,43 @@ namespace Volo.Abp.TextTemplating
{
Check.NotNullOrWhiteSpace(templateName, nameof(templateName));
var templateDefinition = _templateDefinitionManager.Get(templateName);
var content = await _templateContentProvider.GetContentOrNullAsync(
templateName,
templateDefinition,
cultureName
);
var parsedTemplate = Template.Parse(content);
if (templateDefinition.LocalizationResource != null)
{
var localizer = _stringLocalizerFactory.Create(templateDefinition.LocalizationResource);
content = Localize(localizer, content);
}
var renderedContent = await Template.Parse(content).RenderAsync(model);
if (templateDefinition.Layout != null)
{
renderedContent = await RenderAsync(
templateDefinition.Layout,
new
{
content = renderedContent
},
cultureName: cultureName
);
}
return await parsedTemplate.RenderAsync(model);
return renderedContent;
}
public string Localize(IStringLocalizer localizer, string text)
{
return new Regex("\\{\\{#L:.+?\\}\\}")
.Replace(
text,
match => localizer[match.Value.Substring(5, match.Length - 7)]
);
}
}
}

7
framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj

@ -7,13 +7,6 @@
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\Emailing\TestTemplates\*\*.tpl" />
<None Remove="Volo\Abp\Emailing\TestTemplates\*\*.tpl" />
<EmbeddedResource Include="Volo\Abp\Emailing\Localization\*.json" />
<None Remove="Volo\Abp\Emailing\Localization\*.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Emailing\Volo.Abp.Emailing.csproj" />
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />

10
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs

@ -1,6 +1,4 @@
using Volo.Abp.Autofac;
using Volo.Abp.Emailing.Localization;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@ -18,14 +16,6 @@ namespace Volo.Abp.Emailing
{
options.FileSets.AddEmbedded<AbpEmailingTestModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<AbpEmailingTestResource>()
.AddVirtualJson("/Volo/Abp/Emailing/Localization");
});
}
}
}

65
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateRender_Tests.cs

@ -1,65 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Emailing.Templates;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Emailing
{
public class EmailTemplateRender_Tests : AbpIntegratedTest<AbpEmailingTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
private readonly ITemplateRender _templateRender;
public EmailTemplateRender_Tests()
{
_templateRender = GetRequiredService<ITemplateRender>();
}
[Fact]
public async Task RenderAsync()
{
var template = "Hello {{email}} {{ for order in orders }}{{ order.id }}:{{ order.name }},{{ end }}";
var model = new ModelClass
{
Email = "john@abp.io",
Orders = new List<ModelClass.Order>
{
new ModelClass.Order
{
Id = "1",
Name = "iphone"
},
new ModelClass.Order
{
Id = "2",
Name = "ipad"
}
}
};
var result = await _templateRender.RenderAsync(template, model);
result.ShouldBe("Hello john@abp.io 1:iphone,2:ipad,");
}
public class ModelClass
{
public string Email { get; set; }
public List<Order> Orders { get; set; }
public class Order
{
public string Id { get; set; }
public string Name { get; set; }
}
}
}
}

54
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs

@ -1,54 +0,0 @@
using System;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Emailing.Templates;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Emailing
{
public class EmailTemplateStore_Tests : AbpIntegratedTest<AbpEmailingTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
private readonly IEmailTemplateProvider _emailTemplateProvider;
public EmailTemplateStore_Tests()
{
_emailTemplateProvider = GetRequiredService<IEmailTemplateProvider>();
}
[Fact]
public async Task Should_Get_Registered_Template()
{
var template = await _emailTemplateProvider.GetAsync("template1", "tr");
template.Content.ShouldContain("Lütfen aşağıdaki bağlantıya tıklayarak e-posta adresinizi onaylayın.");
}
[Fact]
public async Task Should_Get_Default_Culture_Template()
{
var template = await _emailTemplateProvider.GetAsync("template1", "zh-Hans");
template.Content.ShouldContain("Please confirm your email address by clicking the link below.");
}
[Fact]
public async Task Should_Get_Registered_Template_With_Layout()
{
var template = await _emailTemplateProvider.GetAsync("template2", "en");
template.Content.ShouldContain($"<body>{Environment.NewLine} " + "Please confirm your email address by clicking the link below.");
}
[Fact]
public async Task Should_Get_Registered_Template_With_Localize()
{
var template = await _emailTemplateProvider.GetAsync("template3", "tr");
template.Content.ShouldContain("Merhaba Abp");
}
}
}

10
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/AbpEmailingTestResource.cs

@ -1,10 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.Emailing.Localization
{
public class AbpEmailingTestResource
{
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/cs.json

@ -1,6 +0,0 @@
{
"culture": "cs",
"texts": {
"hello": "ahoj"
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/en.json

@ -1,6 +0,0 @@
{
"culture": "en",
"texts": {
"hello": "hello"
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/pl.json

@ -1,6 +0,0 @@
{
"culture": "pl",
"texts": {
"hello": "witaj"
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/pt-BR.json

@ -1,6 +0,0 @@
{
"culture": "pt-BR",
"texts": {
"hello": "Olá"
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/tr.json

@ -1,6 +0,0 @@
{
"culture": "tr",
"texts": {
"hello": "Merhaba"
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/vi.json

@ -1,6 +0,0 @@
{
"culture": "vi",
"texts": {
"hello": "xin chào"
}
}

6
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/Localization/zh-Hant.json

@ -1,6 +0,0 @@
{
"culture": "zh-Hant",
"texts": {
"hello": "哈囉"
}
}

24
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestEmailTemplateProvider.cs

@ -1,24 +0,0 @@
using Volo.Abp.Emailing.Localization;
using Volo.Abp.Emailing.Templates;
using Volo.Abp.Emailing.Templates.VirtualFiles;
namespace Volo.Abp.Emailing
{
public class TestEmailTemplateProvider : EmailTemplateDefinitionProvider
{
public override void Define(IEmailTemplateDefinitionContext context)
{
var template1 = new EmailTemplateDefinition("template1", defaultCultureName: "en", layout: null)
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/TestTemplates/Template1");
context.Add(template1);
var template2 = new EmailTemplateDefinition("template2", layout: StandardEmailTemplates.DefaultLayout)
.AddTemplateVirtualFiles("/Volo/Abp/Emailing/TestTemplates/Template2");
context.Add(template2);
var template3 = new EmailTemplateDefinition("template3", layout: null, singleTemplateFile: true, localizationResource: typeof(AbpEmailingTestResource))
.AddTemplateVirtualFile("/Volo/Abp/Emailing/TestTemplates/Template3/Template.tpl");
context.Add(template3);
}
}
}

4
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template1/en.tpl

@ -1,4 +0,0 @@
Please confirm your email address by clicking the link below.
We may need to send you critical information about our service and it is important that we have an accurate email address.
<a href="#">Confirm email address</a>

4
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template1/tr.tpl

@ -1,4 +0,0 @@
Lütfen aşağıdaki bağlantıya tıklayarak e-posta adresinizi onaylayın.
Size hizmetimizle ilgili kritik bilgileri göndermemiz gerekebilir ve doğru bir e-posta adresimizin olması önemlidir.
<a href="#">E-posta adresini onayla</a>

4
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template2/en.tpl

@ -1,4 +0,0 @@
Please confirm your email address by clicking the link below.
We may need to send you critical information about our service and it is important that we have an accurate email address.
<a href="#">Confirm email address</a>

1
framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/Template3/Template.tpl

@ -1 +0,0 @@
{{#L:hello}} Abp

63
framework/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/TemplateLocalizer_Tests.cs

@ -1,63 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Shouldly;
using Volo.Abp.Localization.TestResources.Source;
using Volo.Abp.Modularity;
using Volo.Abp.Testing;
using Volo.Abp.VirtualFileSystem;
using Xunit;
namespace Volo.Abp.Localization
{
public class TemplateLocalizer_Tests : AbpIntegratedTest<TemplateLocalizer_Tests.TestModule>
{
private readonly ITemplateLocalizer _templateLocalizer;
private readonly IStringLocalizer<LocalizationTestResource> _testResource;
public TemplateLocalizer_Tests()
{
_testResource = GetRequiredService<IStringLocalizer<LocalizationTestResource>>();
_templateLocalizer = GetRequiredService<ITemplateLocalizer>();
}
[Fact]
public void Should_Localize()
{
using (CultureHelper.Use("en"))
{
_templateLocalizer.Localize(_testResource, "<p>{{#L:CarPlural}} <b>{{#L:Universe}}</b></p>")
.ShouldBe("<p>Cars <b>Universe</b></p>");
}
}
[Fact]
public void Should_Work_Even_If_No_Text_To_Localize()
{
using (CultureHelper.Use("en"))
{
_templateLocalizer.Localize(_testResource, "<p>test</p>")
.ShouldBe("<p>test</p>");
}
}
[DependsOn(typeof(AbpTestBaseModule))]
[DependsOn(typeof(AbpLocalizationModule))]
public class TestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpLocalization_Tests.TestModule>();
});
Configure<AbpLocalizationOptions>(options =>
{
options.Resources
.Add<LocalizationTestResource>("en")
.AddVirtualJson("/Volo/Abp/Localization/TestResources/Source");
});
}
}
}
}
Loading…
Cancel
Save