diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 07a67830be..a45a1a958e 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -200,15 +200,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BackgroundWorkers" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BackgroundJobs.Tests", "test\Volo.Abp.BackgroundJobs.Tests\Volo.Abp.BackgroundJobs.Tests.csproj", "{D86548EA-7047-4623-8824-F6285CD254AA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BackgroundJobs.Abstractions", "src\Volo.Abp.BackgroundJobs.Abstractions\Volo.Abp.BackgroundJobs.Abstractions.csproj", "{EB9C3B4D-FEBD-4691-8F34-AAC2C13F6F2F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BackgroundJobs.Abstractions", "src\Volo.Abp.BackgroundJobs.Abstractions\Volo.Abp.BackgroundJobs.Abstractions.csproj", "{EB9C3B4D-FEBD-4691-8F34-AAC2C13F6F2F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BackgroundJobs.HangFire", "src\Volo.Abp.BackgroundJobs.HangFire\Volo.Abp.BackgroundJobs.HangFire.csproj", "{35AC93EF-E383-4F4E-839D-6EE1C62681F1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BackgroundJobs.HangFire", "src\Volo.Abp.BackgroundJobs.HangFire\Volo.Abp.BackgroundJobs.HangFire.csproj", "{35AC93EF-E383-4F4E-839D-6EE1C62681F1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.HangFire", "src\Volo.Abp.HangFire\Volo.Abp.HangFire.csproj", "{EE01E964-E60E-4C3C-BCF0-AF1A0C0A3DC9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.HangFire", "src\Volo.Abp.HangFire\Volo.Abp.HangFire.csproj", "{EE01E964-E60E-4C3C-BCF0-AF1A0C0A3DC9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BackgroundJobs.RabbitMQ", "src\Volo.Abp.BackgroundJobs.RabbitMQ\Volo.Abp.BackgroundJobs.RabbitMQ.csproj", "{DA7A2C04-E8C4-48AA-A37E-27C25BCE280A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.BackgroundJobs.RabbitMQ", "src\Volo.Abp.BackgroundJobs.RabbitMQ\Volo.Abp.BackgroundJobs.RabbitMQ.csproj", "{DA7A2C04-E8C4-48AA-A37E-27C25BCE280A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.RabbitMQ", "src\Volo.Abp.RabbitMQ\Volo.Abp.RabbitMQ.csproj", "{D91DE561-F403-416F-BD0B-DBF0BA1C4447}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.RabbitMQ", "src\Volo.Abp.RabbitMQ\Volo.Abp.RabbitMQ.csproj", "{D91DE561-F403-416F-BD0B-DBF0BA1C4447}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Emailing.Tests", "test\Volo.Abp.Emailing.Tests\Volo.Abp.Emailing.Tests.csproj", "{D3E07597-BB3D-4249-B873-607E2C128C0E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -592,6 +594,10 @@ Global {D91DE561-F403-416F-BD0B-DBF0BA1C4447}.Debug|Any CPU.Build.0 = Debug|Any CPU {D91DE561-F403-416F-BD0B-DBF0BA1C4447}.Release|Any CPU.ActiveCfg = Release|Any CPU {D91DE561-F403-416F-BD0B-DBF0BA1C4447}.Release|Any CPU.Build.0 = Release|Any CPU + {D3E07597-BB3D-4249-B873-607E2C128C0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3E07597-BB3D-4249-B873-607E2C128C0E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3E07597-BB3D-4249-B873-607E2C128C0E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3E07597-BB3D-4249-B873-607E2C128C0E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -693,6 +699,7 @@ Global {EE01E964-E60E-4C3C-BCF0-AF1A0C0A3DC9} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {DA7A2C04-E8C4-48AA-A37E-27C25BCE280A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {D91DE561-F403-416F-BD0B-DBF0BA1C4447} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {D3E07597-BB3D-4249-B873-607E2C128C0E} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs index 14d7b5d1e2..90e4b8bcd6 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/VirtualFileSystemApplicationBuilderExtensions.cs @@ -1,9 +1,5 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.FileProviders; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.VirtualFileSystem; -using Volo.Abp.VirtualFileSystem; namespace Microsoft.AspNetCore.Builder { diff --git a/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj b/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj index c711697c91..a91be8faf5 100644 --- a/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj +++ b/framework/src/Volo.Abp.Emailing/Volo.Abp.Emailing.csproj @@ -15,6 +15,7 @@ + diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs index afaf0b92fa..d4b6c4e2e8 100644 --- a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/AbpEmailingModule.cs @@ -1,9 +1,14 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Modularity; using Volo.Abp.Settings; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Emailing { + [DependsOn( + typeof(AbpSettingsModule), + typeof(AbpVirtualFileSystemModule) + )] public class AbpEmailingModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplate.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplate.cs new file mode 100644 index 0000000000..1d4c29053f --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplate.cs @@ -0,0 +1,12 @@ +namespace Volo.Abp.Emailing.Templates +{ + public class EmailTemplate + { + public string Content { get; } + + public EmailTemplate(string content) + { + Content = content; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinition.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinition.cs new file mode 100644 index 0000000000..d852070e8a --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinition.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.Emailing.Templates +{ + public class EmailTemplateDefinition + { + public string Name { get; } + + public Dictionary Properties { get; } + + /// + /// Gets/sets a key-value on the . + /// + /// Name of the property + /// + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. + /// + public object this[string name] + { + get => Properties.GetOrDefault(name); + set => Properties[name] = value; + } + + public EmailTemplateDefinition([NotNull]string name) + { + Name = Check.NotNullOrWhiteSpace(name, nameof(name)); + Properties = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionDictionary.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionDictionary.cs new file mode 100644 index 0000000000..09bc33ec97 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateDefinitionDictionary.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Emailing.Templates +{ + public class EmailTemplateDefinitionDictionary : Dictionary + { + + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateOptions.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateOptions.cs new file mode 100644 index 0000000000..d9bf02aae9 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateOptions.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Volo.Abp.Emailing.Templates.Virtual; + +namespace Volo.Abp.Emailing.Templates +{ + public class EmailTemplateOptions + { + public List Providers { get; } + + public EmailTemplateDefinitionDictionary Templates { get; } + + public EmailTemplateOptions() + { + Providers = new List + { + new VirtualFileEmailTemplateProvider() + }; + + Templates = new EmailTemplateDefinitionDictionary(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProviderContext.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProviderContext.cs new file mode 100644 index 0000000000..c1fbc311ba --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateProviderContext.cs @@ -0,0 +1,20 @@ +using System; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Emailing.Templates +{ + public class EmailTemplateProviderContext : IServiceProviderAccessor + { + public string Name { get; } + + public IServiceProvider ServiceProvider { get; } + + public EmailTemplate Template { get; set; } + + public EmailTemplateProviderContext(string name, IServiceProvider serviceProvider) + { + Name = name; + ServiceProvider = serviceProvider; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateStore.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateStore.cs new file mode 100644 index 0000000000..231c86f653 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/EmailTemplateStore.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Emailing.Templates +{ + public class EmailTemplateStore : IEmailTemplateStore, ITransientDependency + { + protected IServiceProvider ServiceProvider { get; } + protected EmailTemplateOptions Options { get; } + + public EmailTemplateStore(IOptions options, IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + Options = options.Value; + } + + public async Task GetAsync(string name) + { + using (var scope = ServiceProvider.CreateScope()) + { + var context = new EmailTemplateProviderContext(name, scope.ServiceProvider); + foreach (var provider in Options.Providers) + { + await provider.ProvideAsync(context); + } + + if (context.Template == null) + { + //TODO: Return a default email template! + throw new NotImplementedException(); + } + + return context.Template; + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateProvider.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateProvider.cs new file mode 100644 index 0000000000..4c05e04f30 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateProvider.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Emailing.Templates +{ + public interface IEmailTemplateProvider + { + Task ProvideAsync(EmailTemplateProviderContext context); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateStore.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateStore.cs new file mode 100644 index 0000000000..ae35725fff --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/IEmailTemplateStore.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Emailing.Templates +{ + public interface IEmailTemplateStore + { + Task GetAsync(string name); + } +} diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/EmailTemplateDefinitionExtensions.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/EmailTemplateDefinitionExtensions.cs new file mode 100644 index 0000000000..2bcd3984d1 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/EmailTemplateDefinitionExtensions.cs @@ -0,0 +1,16 @@ +namespace Volo.Abp.Emailing.Templates.Virtual +{ + public static class EmailTemplateDefinitionExtensions + { + public static EmailTemplateDefinition SetVirtualFilePath(this EmailTemplateDefinition emailTemplateDefinition, string path) + { + emailTemplateDefinition[VirtualFileEmailTemplateProvider.VirtualFilePathKey] = path; + return emailTemplateDefinition; + } + + public static string GetVirtualFilePathOrNull(this EmailTemplateDefinition emailTemplateDefinition) + { + return emailTemplateDefinition[VirtualFileEmailTemplateProvider.VirtualFilePathKey] as string; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/VirtualFileEmailTemplateOptions.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/VirtualFileEmailTemplateOptions.cs new file mode 100644 index 0000000000..0103ac27dc --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/VirtualFileEmailTemplateOptions.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Emailing.Templates.Virtual +{ + public class VirtualFileEmailTemplateOptions + { + public IDictionary Templates { get; } + + public VirtualFileEmailTemplateOptions() + { + Templates = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/VirtualFileEmailTemplateProvider.cs b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/VirtualFileEmailTemplateProvider.cs new file mode 100644 index 0000000000..f5c3dece34 --- /dev/null +++ b/framework/src/Volo.Abp.Emailing/Volo/Abp/Emailing/Templates/Virtual/VirtualFileEmailTemplateProvider.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Options; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.Emailing.Templates.Virtual +{ + public class VirtualFileEmailTemplateProvider : IEmailTemplateProvider + { + public const string VirtualFilePathKey = "VirtualFilePath"; + + public Task ProvideAsync(EmailTemplateProviderContext context) + { + var templateDefinition = FindTemplateDefinition(context); + if (templateDefinition == null) + { + return Task.CompletedTask; + } + + var fileInfo = FindVirtualFileInfo(context, templateDefinition); + if (fileInfo == null) + { + return Task.CompletedTask; + } + + context.Template = new EmailTemplate(fileInfo.ReadAsString()); + return Task.CompletedTask; + } + + protected virtual EmailTemplateDefinition FindTemplateDefinition(EmailTemplateProviderContext context) + { + return context + .ServiceProvider + .GetRequiredService>() + .Value + .Templates + .GetOrDefault(context.Name); + } + + protected virtual IFileInfo FindVirtualFileInfo(EmailTemplateProviderContext context, EmailTemplateDefinition templateDefinition) + { + var virtualFilePath = templateDefinition?.GetVirtualFilePathOrNull(); + if (virtualFilePath == null) + { + return null; + } + + var virtualFileProvider = context.ServiceProvider.GetRequiredService(); + + var fileInfo = virtualFileProvider.GetFileInfo(virtualFilePath); + if (fileInfo?.Exists != true) + { + return null; + } + + return fileInfo; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingDefinition.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingDefinition.cs index 74a4a48f6c..d65d143362 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingDefinition.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingDefinition.cs @@ -28,7 +28,7 @@ /// /// Can be used to store a custom object related to this setting. /// - public object CustomData { get; set; } + public object CustomData { get; set; } //TODO: Convert to dictionary! //TODO: Add Properties dictionary for custom stuff (and remove CustomData) diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj b/framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj new file mode 100644 index 0000000000..c3927589af --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo.Abp.Emailing.Tests.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp2.1 + latest + true + false + false + false + + + + + + + + + + + + + + + diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs new file mode 100644 index 0000000000..d45fab7d32 --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Emailing.Templates; +using Volo.Abp.Emailing.Templates.Virtual; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.Emailing +{ + [DependsOn( + typeof(AbpEmailingModule), + typeof(AbpTestBaseModule))] + public class AbpEmailingTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + context.Services.Configure(options => + { + options.Templates["template1"] = + new EmailTemplateDefinition("template1") + .SetVirtualFilePath("/Volo/Abp/Emailing/TestTemplates/template1.html"); + }); + } + } +} diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs new file mode 100644 index 0000000000..023b6404f4 --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/EmailTemplateStore_Tests.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Emailing.Templates; +using Xunit; + +namespace Volo.Abp.Emailing +{ + public class EmailTemplateStore_Tests : AbpIntegratedTest + { + private readonly IEmailTemplateStore _emailTemplateStore; + + public EmailTemplateStore_Tests() + { + _emailTemplateStore = GetRequiredService(); + } + + [Fact] + public async Task Should_Get_Registered_Template() + { + var template = await _emailTemplateStore.GetAsync("template1"); + template.Content.ShouldContain("This is a test template!"); + } + } +} diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/template1.html b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/template1.html new file mode 100644 index 0000000000..5c98393c69 --- /dev/null +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/TestTemplates/template1.html @@ -0,0 +1,9 @@ + + + + + + + This is a test template! + + \ No newline at end of file