diff --git a/src/scripting/Elsa.Scripting.Liquid/Extensions/LiquidServiceCollectionExtensions.cs b/src/scripting/Elsa.Scripting.Liquid/Extensions/LiquidServiceCollectionExtensions.cs index faeb8e333..e7253eed3 100644 --- a/src/scripting/Elsa.Scripting.Liquid/Extensions/LiquidServiceCollectionExtensions.cs +++ b/src/scripting/Elsa.Scripting.Liquid/Extensions/LiquidServiceCollectionExtensions.cs @@ -1,3 +1,4 @@ +using System; using Elsa.Expressions; using Elsa.Scripting.Liquid.Filters; using Elsa.Scripting.Liquid.Options; @@ -15,7 +16,9 @@ namespace Elsa.Scripting.Liquid.Extensions .AddMemoryCache() .AddNotificationHandlers(typeof(LiquidServiceCollectionExtensions)) .AddScoped() - .AddLiquidFilter("json"); + .AddSingleton() + .AddLiquidFilter("json") + .AddLiquidFilter("base64"); } public static IServiceCollection AddLiquidFilter(this IServiceCollection services, string name) where T : class, ILiquidFilter @@ -24,5 +27,11 @@ namespace Elsa.Scripting.Liquid.Extensions services.AddScoped(); return services; } + + public static IServiceCollection RegisterLiquidTag(this IServiceCollection services, Action configure) + { + services.Configure(options => options.ParserConfiguration.Add(configure)); + return services; + } } } \ No newline at end of file diff --git a/src/scripting/Elsa.Scripting.Liquid/Filters/Base64Filter.cs b/src/scripting/Elsa.Scripting.Liquid/Filters/Base64Filter.cs new file mode 100644 index 000000000..89c3265e2 --- /dev/null +++ b/src/scripting/Elsa.Scripting.Liquid/Filters/Base64Filter.cs @@ -0,0 +1,42 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Elsa.Scripting.Liquid.Services; +using Fluid; +using Fluid.Values; +using Newtonsoft.Json; + +namespace Elsa.Scripting.Liquid.Filters +{ + public class Base64Filter : ILiquidFilter + { + public ValueTask ProcessAsync(FluidValue input, FilterArguments arguments, TemplateContext context) + { + var text = InputToString(input); + + if (text == null) + return new ValueTask(NilValue.Instance); + + var bytes = Encoding.UTF8.GetBytes(text); + var base64 = Convert.ToBase64String(bytes); + + return new ValueTask(new StringValue(base64)); + } + + private string? InputToString(FluidValue input) + { + return input.Type switch + { + FluidValues.Array => JsonConvert.SerializeObject(input.Enumerate().Select(o => o.ToObjectValue())), + FluidValues.Boolean => input.ToBooleanValue().ToString(), + FluidValues.Nil => null, + FluidValues.Number => input.ToNumberValue().ToString(CultureInfo.InvariantCulture), + FluidValues.DateTime or FluidValues.Dictionary or FluidValues.Object => JsonConvert.SerializeObject(input.ToObjectValue()), + FluidValues.String => input.ToStringValue(), + _ => throw new ArgumentOutOfRangeException(nameof(input), "Unrecognized FluidValue") + }; + } + } +} \ No newline at end of file diff --git a/src/scripting/Elsa.Scripting.Liquid/Options/LiquidOptions.cs b/src/scripting/Elsa.Scripting.Liquid/Options/LiquidOptions.cs index 6153a8d61..5ba3e036e 100644 --- a/src/scripting/Elsa.Scripting.Liquid/Options/LiquidOptions.cs +++ b/src/scripting/Elsa.Scripting.Liquid/Options/LiquidOptions.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using Elsa.Scripting.Liquid.Services; namespace Elsa.Scripting.Liquid.Options { public class LiquidOptions { - public Dictionary FilterRegistrations { get; } = new Dictionary(); + public Dictionary FilterRegistrations { get; } = new(); + public IList> ParserConfiguration { get; } = new List>(); } } diff --git a/src/scripting/Elsa.Scripting.Liquid/Services/LiquidParser.cs b/src/scripting/Elsa.Scripting.Liquid/Services/LiquidParser.cs new file mode 100644 index 000000000..e941632f7 --- /dev/null +++ b/src/scripting/Elsa.Scripting.Liquid/Services/LiquidParser.cs @@ -0,0 +1,15 @@ +using Elsa.Scripting.Liquid.Options; +using Fluid; +using Microsoft.Extensions.Options; + +namespace Elsa.Scripting.Liquid.Services +{ + public class LiquidParser : FluidParser + { + public LiquidParser(IOptions options) + { + foreach (var configuration in options.Value.ParserConfiguration) + configuration(this); + } + } +} \ No newline at end of file diff --git a/src/scripting/Elsa.Scripting.Liquid/Services/LiquidTemplateManager.cs b/src/scripting/Elsa.Scripting.Liquid/Services/LiquidTemplateManager.cs index 0662de41d..a4c0dbff6 100644 --- a/src/scripting/Elsa.Scripting.Liquid/Services/LiquidTemplateManager.cs +++ b/src/scripting/Elsa.Scripting.Liquid/Services/LiquidTemplateManager.cs @@ -11,12 +11,14 @@ namespace Elsa.Scripting.Liquid.Services { public class LiquidTemplateManager : ILiquidTemplateManager { + private readonly LiquidParser _parser; private readonly IMemoryCache _memoryCache; private readonly IServiceProvider _serviceProvider; private readonly LiquidOptions _options; - public LiquidTemplateManager(IMemoryCache memoryCache, IOptions options, IServiceProvider serviceProvider) + public LiquidTemplateManager(LiquidParser parser, IMemoryCache memoryCache, IOptions options, IServiceProvider serviceProvider) { + _parser = parser; _memoryCache = memoryCache; _serviceProvider = serviceProvider; _options = options.Value; @@ -52,6 +54,6 @@ namespace Elsa.Scripting.Liquid.Services public bool Validate(string template, out string error) => TryParse(template, out _, out error); - private static bool TryParse(string template, out IFluidTemplate result, out string error) => new FluidParser().TryParse(template, out result, out error); + private bool TryParse(string template, out IFluidTemplate result, out string error) => _parser.TryParse(template, out result, out error); } } \ No newline at end of file