From e10a74b31f04b7e6123c11f66ae23d6ed363bea5 Mon Sep 17 00:00:00 2001 From: Jason Finch Date: Sun, 19 Sep 2021 21:47:18 +1000 Subject: [PATCH] feat (Liquid): Add TemplateOptions as a configurable property. Added test for complex object. --- .../FluentEmail.Liquid/LiquidRenderer.cs | 4 +- .../LiquidRendererOptions.cs | 5 ++ .../ComplexModel/ComplexModelRenderTests.cs | 71 +++++++++++++++++++ .../ComplexModel/ParentModel.cs | 17 +++++ .../ComplexModel/TestData.cs | 9 +++ .../FluentEmail.Liquid.Tests.csproj | 1 + 6 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 test/FluentEmail.Liquid.Tests/ComplexModel/ComplexModelRenderTests.cs create mode 100644 test/FluentEmail.Liquid.Tests/ComplexModel/ParentModel.cs create mode 100644 test/FluentEmail.Liquid.Tests/ComplexModel/TestData.cs diff --git a/src/Renderers/FluentEmail.Liquid/LiquidRenderer.cs b/src/Renderers/FluentEmail.Liquid/LiquidRenderer.cs index ab92cbe0..fe53645a 100644 --- a/src/Renderers/FluentEmail.Liquid/LiquidRenderer.cs +++ b/src/Renderers/FluentEmail.Liquid/LiquidRenderer.cs @@ -34,7 +34,7 @@ public async Task ParseAsync(string template, T model, bool isHtml = var fileProvider = rendererOptions.FileProvider; var viewTemplate = ParseTemplate(template); - var context = new TemplateContext(model) + var context = new TemplateContext(model, rendererOptions.TemplateOptions) { // provide some services to all statements AmbientValues = @@ -56,7 +56,7 @@ public async Task ParseAsync(string template, T model, bool isHtml = if (context.AmbientValues.TryGetValue("Layout", out var layoutPath)) { context.AmbientValues["Body"] = body; - var layoutTemplate = ParseLiquidFile((string) layoutPath, fileProvider!); + var layoutTemplate = ParseLiquidFile((string)layoutPath, fileProvider!); return await layoutTemplate.RenderAsync(context, rendererOptions.TextEncoder); } diff --git a/src/Renderers/FluentEmail.Liquid/LiquidRendererOptions.cs b/src/Renderers/FluentEmail.Liquid/LiquidRendererOptions.cs index feed0c4a..8f8df34b 100644 --- a/src/Renderers/FluentEmail.Liquid/LiquidRendererOptions.cs +++ b/src/Renderers/FluentEmail.Liquid/LiquidRendererOptions.cs @@ -25,5 +25,10 @@ public class LiquidRendererOptions /// File provider to use, used when resolving references in templates, like master layout. /// public IFileProvider? FileProvider { get; set; } + + /// + /// Set custom Template Options for Fluid + /// + public TemplateOptions TemplateOptions { get; set; } = new(); } } \ No newline at end of file diff --git a/test/FluentEmail.Liquid.Tests/ComplexModel/ComplexModelRenderTests.cs b/test/FluentEmail.Liquid.Tests/ComplexModel/ComplexModelRenderTests.cs new file mode 100644 index 00000000..04e642ee --- /dev/null +++ b/test/FluentEmail.Liquid.Tests/ComplexModel/ComplexModelRenderTests.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using FluentAssertions; +using FluentEmail.Core; +using Fluid; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Options; +using NUnit.Framework; + +namespace FluentEmail.Liquid.Tests.ComplexModel +{ + public class ComplexModelRenderTests + { + public ComplexModelRenderTests() + { + SetupRenderer(); + } + + [Test] + public void Can_Render_Complex_Model_Properties() + { + var model = new ParentModel + { + ParentName = new NameDetails { Firstname = "Luke", Surname = "Dinosaur" }, + ChildrenNames = new List + { + new NameDetails { Firstname = "ChildFirstA", Surname = "ChildLastA" }, + new NameDetails { Firstname = "ChildFirstB", Surname = "ChildLastB" } + } + }; + + var expected = @" +Parent: Luke +Children: + +* ChildFirstA ChildLastA +* ChildFirstB ChildLastB +"; + + var email = Email + .From(TestData.FromEmail) + .To(TestData.ToEmail) + .Subject(TestData.Subject) + .UsingTemplate(Template(), model); + email.Data.Body.Should().Be(expected); + } + + private string Template() + { + return @" +Parent: {{ ParentName.Firstname }} +Children: +{% for Child in ChildrenNames %} +* {{ Child.Firstname }} {{ Child.Surname }}{% endfor %} +"; + } + + private static void SetupRenderer( + IFileProvider fileProvider = null, + Action configureTemplateContext = null) + { + var options = new LiquidRendererOptions + { + FileProvider = fileProvider, + ConfigureTemplateContext = configureTemplateContext, + TemplateOptions = new TemplateOptions { MemberAccessStrategy = new UnsafeMemberAccessStrategy() } + }; + Email.DefaultRenderer = new LiquidRenderer(Options.Create(options)); + } + } +} \ No newline at end of file diff --git a/test/FluentEmail.Liquid.Tests/ComplexModel/ParentModel.cs b/test/FluentEmail.Liquid.Tests/ComplexModel/ParentModel.cs new file mode 100644 index 00000000..029f3449 --- /dev/null +++ b/test/FluentEmail.Liquid.Tests/ComplexModel/ParentModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace FluentEmail.Liquid.Tests +{ + public class ParentModel + { + public string Id { get; set; } + public NameDetails ParentName { get; set; } + public List ChildrenNames { get; set; } = new List(); + } + + public class NameDetails + { + public string Firstname { get; set; } + public string Surname { get; set; } + } +} \ No newline at end of file diff --git a/test/FluentEmail.Liquid.Tests/ComplexModel/TestData.cs b/test/FluentEmail.Liquid.Tests/ComplexModel/TestData.cs new file mode 100644 index 00000000..e1dd598c --- /dev/null +++ b/test/FluentEmail.Liquid.Tests/ComplexModel/TestData.cs @@ -0,0 +1,9 @@ +namespace FluentEmail.Liquid.Tests +{ + public static class TestData + { + public const string ToEmail = "bob@test.com"; + public const string FromEmail = "johno@test.com"; + public const string Subject = "sup dawg"; + } +} \ No newline at end of file diff --git a/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj b/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj index e2363f10..e2c5dcfc 100644 --- a/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj +++ b/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj @@ -21,6 +21,7 @@ +