From 175ce6a36f92b86350e344d7dff392687ea328b6 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Mon, 22 Jun 2020 11:10:21 +0200 Subject: [PATCH] Simplified. (#538) * Scripting simplified. --- .../HandleRules/RuleEventFormatter.cs | 10 +- .../Scripting/ExecutionContext.cs | 50 ++++- .../Extensions/DateTimeJintExtension.cs | 21 +-- .../Scripting/Extensions/HttpJintExtension.cs | 2 + .../Extensions/StringJintExtension.cs | 37 ++-- .../Scripting/IScriptEngine.cs | 22 ++- .../Scripting/JintScriptEngine.cs | 176 +++--------------- .../Scripting/ScriptOperations.cs | 32 ++-- .../Scripting/ScriptOptions.cs | 23 +++ .../Scripting/ScriptVars.cs | 56 +----- .../Contents/ContentOperationContext.cs | 11 +- .../Contents/Counter/CounterJintExtension.cs | 1 - .../Search/SearchManager.cs | 2 +- .../Queries/Optimizer.cs | 1 - .../Config/IdentityServerExtensions.cs | 1 - .../Scripting/JintScriptEngineHelperTests.cs | 40 +++- .../Scripting/JintScriptEngineTests.cs | 61 +++--- .../Assets/AssetChangedTriggerHandlerTests.cs | 8 +- .../Comments/CommentTriggerHandlerTests.cs | 8 +- .../ContentChangedTriggerHandlerTests.cs | 8 +- .../Contents/ContentDomainObjectTests.cs | 43 +++-- .../Counter/CounterJintExtensionTests.cs | 4 +- .../Contents/Queries/ScriptContentTests.cs | 9 +- .../SchemaChangedTriggerHandlerTests.cs | 8 +- .../Search/SearchManagerTests.cs | 2 +- 25 files changed, 291 insertions(+), 345 deletions(-) create mode 100644 backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs index 67e901325..e9f47c02d 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; using NodaTime.Text; @@ -116,7 +117,14 @@ namespace Squidex.Domain.Apps.Core.HandleRules ["event"] = @event }; - return scriptEngine.Interpolate(vars, script); + var result = scriptEngine.Execute(vars, script).ToString(); + + if (result == "undefined") + { + return GlobalFallback; + } + + return result; } var parts = BuildParts(text, @event); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs index 63e63bc4f..bad22c0af 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ExecutionContext.cs @@ -9,6 +9,9 @@ using System; using System.Collections.Generic; using System.Threading; using Jint; +using Jint.Native; +using Jint.Native.Object; +using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Scripting { @@ -22,6 +25,8 @@ namespace Squidex.Domain.Apps.Core.Scripting public CancellationToken CancellationToken { get; } + public bool IsAsync { get; private set; } + internal ExecutionContext(Engine engine, CancellationToken cancellationToken, ExceptionHandler? exceptionHandler = null) : base(StringComparer.OrdinalIgnoreCase) { @@ -32,16 +37,55 @@ namespace Squidex.Domain.Apps.Core.Scripting this.exceptionHandler = exceptionHandler; } + public void MarkAsync() + { + IsAsync = true; + } + public void Fail(Exception exception) { exceptionHandler?.Invoke(exception); } - public ExecutionContext SetValue(string key, object value) + public void AddVariables(ScriptVars vars, ScriptOptions options) { - this[key] = value; + var engine = Engine; + + if (options.AsContext) + { + var contextInstance = new ObjectInstance(engine); + + foreach (var (key, value) in vars) + { + var property = key.ToCamelCase(); + + if (value != null) + { + contextInstance.FastAddProperty(property, JsValue.FromObject(engine, value), true, true, true); + + this[property] = value; + } + } + + engine.SetValue("ctx", contextInstance); + engine.SetValue("context", contextInstance); + } + else + { + foreach (var (key, value) in vars) + { + var property = key.ToCamelCase(); + + if (value != null) + { + engine.SetValue(property, value); + + this[property] = value; + } + } + } - return this; + engine.SetValue("async", true); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/DateTimeJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/DateTimeJintExtension.cs index 8ceb9d47b..3fb706c00 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/DateTimeJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/DateTimeJintExtension.cs @@ -14,20 +14,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { public sealed class DateTimeJintExtension : IJintExtension { - private readonly Func formatDate; - - public DateTimeJintExtension() - { - formatDate = new Func(FormatDate); - } - - public void Extend(Engine engine) - { - engine.SetValue("formatTime", formatDate); - engine.SetValue("formatDate", formatDate); - } - - private static JsValue FormatDate(DateTime date, string format) + private readonly Func formatDate = (date, format) => { try { @@ -37,6 +24,12 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { return JsValue.Undefined; } + }; + + public void Extend(Engine engine) + { + engine.SetValue("formatTime", formatDate); + engine.SetValue("formatDate", formatDate); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs index 4f16a56eb..ca9f9d16b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs @@ -45,6 +45,8 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions private async Task GetJsonAsync(ExecutionContext context, string url, Action callback, JsValue? headers) { + context.MarkAsync(); + try { using (var httpClient = httpClientFactory.CreateClient()) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs index ddf775b97..4a7569bbc 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/StringJintExtension.cs @@ -15,27 +15,8 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions public sealed class StringJintExtension : IJintExtension { private delegate JsValue StringSlugifyDelegate(string text, bool single = false); - private readonly StringSlugifyDelegate slugify; - private readonly Func toCamelCase; - private readonly Func toPascalCase; - public StringJintExtension() - { - slugify = new StringSlugifyDelegate(Slugify); - - toCamelCase = new Func(ToCamelCase); - toPascalCase = new Func(ToPascalCase); - } - - public void Extend(Engine engine) - { - engine.SetValue("slugify", slugify); - - engine.SetValue("toCamelCase", toCamelCase); - engine.SetValue("toPascalCase", toPascalCase); - } - - private static JsValue Slugify(string text, bool single = false) + private readonly StringSlugifyDelegate slugify = (text, single) => { try { @@ -45,9 +26,9 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { return JsValue.Undefined; } - } + }; - private static JsValue ToCamelCase(string text) + private readonly Func toCamelCase = text => { try { @@ -57,9 +38,9 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { return JsValue.Undefined; } - } + }; - private static JsValue ToPascalCase(string text) + private readonly Func toPascalCase = text => { try { @@ -69,6 +50,14 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions { return JsValue.Undefined; } + }; + + public void Extend(Engine engine) + { + engine.SetValue("slugify", slugify); + + engine.SetValue("toCamelCase", toCamelCase); + engine.SetValue("toPascalCase", toPascalCase); } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs index 38224bd26..39d0944b2 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/IScriptEngine.cs @@ -13,16 +13,22 @@ namespace Squidex.Domain.Apps.Core.Scripting { public interface IScriptEngine { - Task ExecuteAsync(ScriptVars vars, string script); + Task ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default); - Task ExecuteAndTransformAsync(ScriptVars vars, string script); + Task TransformAsync(ScriptVars vars, string script, ScriptOptions options = default); - Task TransformAsync(ScriptVars vars, string script); + IJsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default); - Task GetAsync(ScriptVars vars, string script); - - bool Evaluate(ScriptVars vars, string script); - - string? Interpolate(ScriptVars vars, string script); + bool Evaluate(ScriptVars vars, string script, ScriptOptions options = default) + { + try + { + return Execute(vars, script, options).Equals(JsonValue.True); + } + catch + { + return false; + } + } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs index 00beb39e3..4917faf80 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs @@ -40,85 +40,29 @@ namespace Squidex.Domain.Apps.Core.Scripting this.extensions = extensions?.ToArray() ?? Array.Empty(); } - public async Task ExecuteAsync(ScriptVars vars, string script) + public async Task ExecuteAsync(ScriptVars vars, string script, ScriptOptions options = default) { Guard.NotNull(vars, nameof(vars)); Guard.NotNullOrEmpty(script, nameof(script)); using (var cts = new CancellationTokenSource(ExecutionTimeout)) { - var tcs = new TaskCompletionSource(); - - using (cts.Token.Register(() => tcs.TrySetCanceled())) - { - var engine = - CreateEngine(vars, true, cts.Token, tcs.TrySetException, true) - .AddDisallow() - .AddReject(); - - engine.SetValue("complete", new Action(value => - { - tcs.TrySetResult(true); - })); - - Execute(engine, script); - - if (engine.GetValue("async") != true) - { - tcs.TrySetResult(true); - } - - await tcs.Task; - } - } - } - - public async Task ExecuteAndTransformAsync(ScriptVars vars, string script) - { - Guard.NotNull(vars, nameof(vars)); - Guard.NotNullOrEmpty(script, nameof(script)); - - using (var cts = new CancellationTokenSource(ExecutionTimeout)) - { - var tcs = new TaskCompletionSource(); + var tcs = new TaskCompletionSource(); using (cts.Token.Register(() => tcs.TrySetCanceled())) { - var engine = - CreateEngine(vars, true, cts.Token, tcs.TrySetException, true) - .AddDisallow() - .AddReject(); + var context = CreateEngine(vars, options, cts.Token, tcs.TrySetException, true); - engine.SetValue("complete", new Action(value => + context.Engine.SetValue("complete", new Action(value => { - tcs.TrySetResult(vars.Data!); - })); - - engine.SetValue("replace", new Action(() => - { - var dataInstance = engine.GetValue("ctx").AsObject().Get("data"); - - if (dataInstance != null && dataInstance.IsObject() && dataInstance.AsObject() is ContentDataObject data) - { - if (!tcs.Task.IsCompleted) - { - if (data.TryUpdate(out var modified)) - { - tcs.TrySetResult(modified); - } - else - { - tcs.TrySetResult(vars.Data!); - } - } - } + tcs.TrySetResult(JsonMapper.Map(value)); })); - Execute(engine, script); + Execute(context.Engine, script); - if (engine.GetValue("async") != true) + if (!context.IsAsync) { - tcs.TrySetResult(vars.Data!); + tcs.TrySetResult(JsonMapper.Map(context.Engine.GetCompletionValue())); } return await tcs.Task; @@ -126,7 +70,7 @@ namespace Squidex.Domain.Apps.Core.Scripting } } - public async Task TransformAsync(ScriptVars vars, string script) + public async Task TransformAsync(ScriptVars vars, string script, ScriptOptions options = default) { Guard.NotNull(vars, nameof(vars)); Guard.NotNullOrEmpty(script, nameof(script)); @@ -137,16 +81,16 @@ namespace Squidex.Domain.Apps.Core.Scripting using (cts.Token.Register(() => tcs.TrySetCanceled())) { - var engine = CreateEngine(vars, true, cts.Token, tcs.TrySetException, true); + var context = CreateEngine(vars, options, cts.Token, tcs.TrySetException, true); - engine.SetValue("complete", new Action(value => + context.Engine.SetValue("complete", new Action(value => { tcs.TrySetResult(vars.Data!); })); - engine.SetValue("replace", new Action(() => + context.Engine.SetValue("replace", new Action(() => { - var dataInstance = engine.GetValue("ctx").AsObject().Get("data"); + var dataInstance = context.Engine.GetValue("ctx").AsObject().Get("data"); if (dataInstance != null && dataInstance.IsObject() && dataInstance.AsObject() is ContentDataObject data) { @@ -164,9 +108,9 @@ namespace Squidex.Domain.Apps.Core.Scripting } })); - Execute(engine, script); + Execute(context.Engine, script); - if (engine.GetValue("async") != true) + if (!context.IsAsync) { tcs.TrySetResult(vars.Data!); } @@ -176,82 +120,19 @@ namespace Squidex.Domain.Apps.Core.Scripting } } - public bool Evaluate(ScriptVars vars, string script) - { - Guard.NotNull(vars, nameof(vars)); - Guard.NotNullOrEmpty(script, nameof(script)); - - try - { - var engine = CreateEngine(vars, false); - - Execute(engine, script); - - var converted = Equals(engine.GetCompletionValue().ToObject(), true); - - return converted; - } - catch - { - return false; - } - } - - public string? Interpolate(ScriptVars vars, string script) + public IJsonValue Execute(ScriptVars vars, string script, ScriptOptions options = default) { Guard.NotNull(vars, nameof(vars)); Guard.NotNullOrEmpty(script, nameof(script)); - try - { - var engine = CreateEngine(vars, false); - - Execute(engine, script); + var context = CreateEngine(vars, options); - var converted = engine.GetCompletionValue().ToObject()?.ToString() ?? "null"; + Execute(context.Engine, script); - return converted == "undefined" ? "null" : converted; - } - catch (Exception ex) - { - return ex.Message; - } + return JsonMapper.Map(context.Engine.GetCompletionValue()); } - public Task GetAsync(ScriptVars vars, string script) - { - Guard.NotNull(vars, nameof(vars)); - Guard.NotNullOrEmpty(script, nameof(script)); - - using (var cts = new CancellationTokenSource(ExecutionTimeout)) - { - var tcs = new TaskCompletionSource(); - - using (cts.Token.Register(() => - { - tcs.TrySetCanceled(); - })) - { - var engine = CreateEngine(vars, true, cts.Token, ex => tcs.TrySetException(ex), true); - - engine.SetValue("complete", new Action(value => - { - tcs.TrySetResult(JsonMapper.Map(value)); - })); - - engine.Execute(script); - - if (engine.GetValue("async") != true) - { - tcs.TrySetResult(JsonMapper.Map(engine.GetCompletionValue())); - } - } - - return tcs.Task; - } - } - - private Engine CreateEngine(ScriptVars vars, bool nested, CancellationToken cancellationToken = default, ExceptionHandler? exceptionHandler = null, bool async = false) + private ExecutionContext CreateEngine(ScriptVars vars, ScriptOptions options, CancellationToken cancellationToken = default, ExceptionHandler? exceptionHandler = null, bool async = false) { var engine = new Engine(options => { @@ -261,9 +142,14 @@ namespace Squidex.Domain.Apps.Core.Scripting options.TimeoutInterval(Timeout); }); - if (async) + if (options.CanDisallow) + { + engine.AddDisallow(); + } + + if (options.CanReject) { - engine.SetValue("async", false); + engine.AddReject(); } foreach (var extension in extensions) @@ -271,16 +157,16 @@ namespace Squidex.Domain.Apps.Core.Scripting extension.Extend(engine); } - var executionvars = new ExecutionContext(engine, cancellationToken, exceptionHandler); + var context = new ExecutionContext(engine, cancellationToken, exceptionHandler); - vars.Add(executionvars, nested); + context.AddVariables(vars, options); foreach (var extension in extensions) { - extension.Extend(executionvars, async); + extension.Extend(context, async); } - return executionvars.Engine; + return context; } private void Execute(Engine engine, string script) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs index af6c51a1c..de3d6643b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOperations.cs @@ -13,36 +13,34 @@ namespace Squidex.Domain.Apps.Core.Scripting { internal static class ScriptOperations { - public static Engine AddDisallow(this Engine engine) - { - engine.SetValue("disallow", new DisallowDelegate(Disallow)); - - return engine; - } + private delegate void MessageDelegate(string? message); - private delegate void DisallowDelegate(string? message); - - private static void Disallow(string? message = null) + private static readonly MessageDelegate Disallow = new MessageDelegate(message => { message = !string.IsNullOrWhiteSpace(message) ? message : "Not allowed"; throw new DomainForbiddenException(message); - } + }); - public static Engine AddReject(this Engine engine) + private static readonly MessageDelegate Reject = new MessageDelegate(message => { - engine.SetValue("reject", new RejectDelegate(Reject)); + var errors = !string.IsNullOrWhiteSpace(message) ? new[] { new ValidationError(message) } : null; + + throw new ValidationException("Script rejected the operation.", errors); + }); + + public static Engine AddDisallow(this Engine engine) + { + engine.SetValue("disallow", Disallow); return engine; } - private delegate void RejectDelegate(string? message); - - private static void Reject(string? message = null) + public static Engine AddReject(this Engine engine) { - var errors = !string.IsNullOrWhiteSpace(message) ? new[] { new ValidationError(message) } : null; + engine.SetValue("reject", Reject); - throw new ValidationException("Script rejected the operation.", errors); + return engine; } } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs new file mode 100644 index 000000000..8eb74efdc --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs @@ -0,0 +1,23 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Scripting +{ + public struct ScriptOptions + { + public bool CanReject { get; set; } + + public bool CanDisallow { get; set; } + + public bool AsContext { get; set; } + + public override string ToString() + { + return $"CanReject={CanReject}, CanDisallow={CanDisallow}, AsContext={AsContext}"; + } + } +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs index 0a8870f68..190bd1a31 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs @@ -9,10 +9,7 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Security.Claims; -using Jint.Native; -using Jint.Native.Object; using Squidex.Domain.Apps.Core.Contents; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Core.Scripting { @@ -41,12 +38,6 @@ namespace Squidex.Domain.Apps.Core.Scripting set => SetValue(value); } - public NamedContentData? Data - { - get => GetValue(); - set => SetValue(value); - } - public Status Status { get => GetValue(); @@ -65,6 +56,12 @@ namespace Squidex.Domain.Apps.Core.Scripting set => SetValue(value); } + public NamedContentData? Data + { + get => GetValue(); + set => SetValue(value); + } + public NamedContentData? DataOld { get => GetValue(); @@ -85,7 +82,7 @@ namespace Squidex.Domain.Apps.Core.Scripting } } - public void SetValue(object? value, [CallerMemberNameAttribute] string? key = null) + public void SetValue(object? value, [CallerMemberName] string? key = null) { if (key != null) { @@ -93,7 +90,7 @@ namespace Squidex.Domain.Apps.Core.Scripting } } - public T GetValue([CallerMemberNameAttribute] string? key = null) + public T GetValue([CallerMemberName] string? key = null) { if (key != null && TryGetValue(key, out var temp) && temp is T result) { @@ -102,42 +99,5 @@ namespace Squidex.Domain.Apps.Core.Scripting return default!; } - - internal void Add(ExecutionContext context, bool nested) - { - var engine = context.Engine; - - if (nested) - { - var contextInstance = new ObjectInstance(engine); - - foreach (var (key, value) in this) - { - var property = key.ToCamelCase(); - - if (value != null) - { - contextInstance.FastAddProperty(property, JsValue.FromObject(engine, value), true, true, true); - context[property] = value; - } - } - - engine.SetValue("ctx", contextInstance); - engine.SetValue("context", contextInstance); - } - else - { - foreach (var (key, value) in this) - { - var property = key.ToCamelCase(); - - if (value != null) - { - engine.SetValue(property, value); - context[property] = value; - } - } - } - } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs index 157fa6db1..902749ed8 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs @@ -26,6 +26,13 @@ namespace Squidex.Domain.Apps.Entities.Contents { public sealed class ContentOperationContext { + private static readonly ScriptOptions ScriptOptions = new ScriptOptions + { + AsContext = true, + CanDisallow = true, + CanReject = true + }; + private readonly IScriptEngine scriptEngine; private readonly IAppProvider appProvider; private readonly IEnumerable factories; @@ -122,7 +129,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return context.Data!; } - return await scriptEngine.ExecuteAndTransformAsync(context, actualScript); + return await scriptEngine.TransformAsync(context, actualScript, ScriptOptions); } public async Task ExecuteScriptAsync(Func script, ScriptVars context) @@ -136,7 +143,7 @@ namespace Squidex.Domain.Apps.Entities.Contents return; } - await scriptEngine.ExecuteAsync(context, GetScript(script)); + await scriptEngine.ExecuteAsync(context, GetScript(script), ScriptOptions); } private void Enrich(ScriptVars context) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs index 574ab7f87..a4d2c91c0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Counter/CounterJintExtension.cs @@ -6,7 +6,6 @@ // ========================================================================== using System; -using System.Threading.Tasks; using Orleans; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Infrastructure; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs b/backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs index 7afba438b..9b7511581 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Search/SearchManager.cs @@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Entities.Search var tasks = searchSources.Select(x => SearchAsync(x, query, context)); - var results = await Task.WhenAll(tasks); + var results = await Task.WhenAll(tasks); return new SearchResults(results.SelectMany(x => x)); } diff --git a/backend/src/Squidex.Infrastructure/Queries/Optimizer.cs b/backend/src/Squidex.Infrastructure/Queries/Optimizer.cs index bbdecf551..396857d11 100644 --- a/backend/src/Squidex.Infrastructure/Queries/Optimizer.cs +++ b/backend/src/Squidex.Infrastructure/Queries/Optimizer.cs @@ -6,7 +6,6 @@ // ========================================================================== using System.Collections.Generic; -using System.Linq; namespace Squidex.Infrastructure.Queries { diff --git a/backend/src/Squidex/Areas/IdentityServer/Config/IdentityServerExtensions.cs b/backend/src/Squidex/Areas/IdentityServer/Config/IdentityServerExtensions.cs index 677361f1e..b151f9865 100644 --- a/backend/src/Squidex/Areas/IdentityServer/Config/IdentityServerExtensions.cs +++ b/backend/src/Squidex/Areas/IdentityServer/Config/IdentityServerExtensions.cs @@ -7,7 +7,6 @@ using System; using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs index 1cd0a7da4..b31090f98 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs @@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = "Hello World" }; - var result = sut.Interpolate(vars, script); + var result = sut.Execute(vars, script).ToString(); Assert.Equal("helloWorld", result); } @@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = "Hello World" }; - var result = sut.Interpolate(vars, script); + var result = sut.Execute(vars, script).ToString(); Assert.Equal("HelloWorld", result); } @@ -90,7 +90,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = "4 Häuser" }; - var result = sut.Interpolate(vars, script); + var result = sut.Execute(vars, script).ToString(); Assert.Equal("4-haeuser", result); } @@ -107,7 +107,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = "4 Häuser" }; - var result = sut.Interpolate(vars, script); + var result = sut.Execute(vars, script).ToString(); Assert.Equal("4-hauser", result); } @@ -119,7 +119,12 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting reject() "; - var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script)); + var options = new ScriptOptions + { + CanReject = true + }; + + var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script, options)); Assert.Empty(ex.Errors); } @@ -131,7 +136,12 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting reject('Not valid') "; - var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script)); + var options = new ScriptOptions + { + CanReject = true + }; + + var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script, options)); Assert.Equal("Not valid", ex.Errors.Single().Message); } @@ -143,7 +153,12 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting disallow() "; - var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script)); + var options = new ScriptOptions + { + CanDisallow = true + }; + + var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script, options)); Assert.Equal("Not allowed", ex.Message); } @@ -155,7 +170,12 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting disallow('Operation not allowed') "; - var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script)); + var options = new ScriptOptions + { + CanDisallow = true + }; + + var ex = await Assert.ThrowsAsync(() => sut.ExecuteAsync(new ScriptVars(), script, options)); Assert.Equal("Operation not allowed", ex.Message); } @@ -173,7 +193,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting }); "; - var result = await sut.GetAsync(new ScriptVars(), script); + var result = await sut.ExecuteAsync(new ScriptVars(), script); httpHandler.ShouldBeMethod(HttpMethod.Get); httpHandler.ShouldBeUrl("http://squidex.io/"); @@ -201,7 +221,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting }, headers); "; - var result = await sut.GetAsync(new ScriptVars(), script); + var result = await sut.ExecuteAsync(new ScriptVars(), script); httpHandler.ShouldBeMethod(HttpMethod.Get); httpHandler.ShouldBeUrl("http://squidex.io/"); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs index 54fa6d2a8..86ca2925f 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs @@ -24,6 +24,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting { public class JintScriptEngineTests { + private readonly ScriptOptions contentOptions = new ScriptOptions + { + CanReject = true, + CanDisallow = true, + AsContext = true + }; + private readonly IHttpClientFactory httpClientFactory = A.Fake(); private readonly JintScriptEngine sut; @@ -84,7 +91,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting x => x "; - var result = await sut.TransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Empty(result); } @@ -122,23 +129,23 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting replace(data); "; - var result = await sut.TransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Equal(expected, result); } [Fact] - public async Task ExecuteAndTransformAsync_should_catch_javascript_error() + public async Task TransformAsync_should_catch_javascript_error() { const string script = @" throw 'Error'; "; - await Assert.ThrowsAsync(() => sut.ExecuteAndTransformAsync(new ScriptVars(), script)); + await Assert.ThrowsAsync(() => sut.TransformAsync(new ScriptVars(), script)); } [Fact] - public async Task ExecuteAndTransformAsync_should_throw_when_script_failed() + public async Task TransformAsync_should_throw_when_script_failed() { var content = new NamedContentData(); var context = new ScriptVars { Data = content }; @@ -147,11 +154,11 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting invalid(); "; - await Assert.ThrowsAsync(() => sut.ExecuteAndTransformAsync(context, script)); + await Assert.ThrowsAsync(() => sut.TransformAsync(context, script, contentOptions)); } [Fact] - public async Task ExecuteAndTransformAsync_should_return_original_content_when_not_replaced() + public async Task TransformAsync_should_return_original_content_when_not_replaced() { var content = new NamedContentData(); var context = new ScriptVars { Data = content }; @@ -160,13 +167,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting var x = 0; "; - var result = await sut.ExecuteAndTransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Empty(result); } [Fact] - public async Task ExecuteAndTransformAsync_should_return_original_content_when_not_replaced_async() + public async Task TransformAsync_should_return_original_content_when_not_replaced_async() { var content = new NamedContentData(); var context = new ScriptVars { Data = content }; @@ -181,13 +188,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting }); "; - var result = await sut.ExecuteAndTransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Empty(result); } [Fact] - public async Task ExecuteAndTransformAsync_should_transform_object() + public async Task TransformAsync_should_transform_object() { var content = new NamedContentData(); @@ -207,13 +214,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting replace(data); "; - var result = await sut.ExecuteAndTransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Equal(expected, result); } [Fact] - public async Task ExecuteAndTransformAsync_should_transform_object_async() + public async Task TransformAsync_should_transform_object_async() { var content = new NamedContentData(); @@ -238,13 +245,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting "; - var result = await sut.ExecuteAndTransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Equal(expected, result); } [Fact] - public async Task ExecuteAndTransformAsync_should_ignore_transformation_when_async_not_set() + public async Task TransformAsync_should_not_ignore_transformation_when_async_not_set() { var content = new NamedContentData(); var context = new ScriptVars { Data = content, Operation = "MyOperation" }; @@ -260,13 +267,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting "; - var result = await sut.ExecuteAndTransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); - Assert.Empty( result); + Assert.NotEmpty(result); } [Fact] - public async Task ExecuteAndTransformAsync_should_timeout_when_replace_never_called() + public async Task TransformAsync_should_timeout_when_replace_never_called() { var content = new NamedContentData(); var context = new ScriptVars { Data = content, Operation = "MyOperation" }; @@ -282,11 +289,11 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting "; - await Assert.ThrowsAnyAsync(() => sut.ExecuteAndTransformAsync(context, script)); + await Assert.ThrowsAnyAsync(() => sut.TransformAsync(context, script, contentOptions)); } [Fact] - public async Task ExecuteAndTransformAsync_should_transform_content_and_return_with_execute_transform() + public async Task TransformAsync_should_transform_content_and_return_with_execute_transform() { var content = new NamedContentData() @@ -318,13 +325,13 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting replace(data); "; - var result = await sut.ExecuteAndTransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Equal(expected, result); } [Fact] - public async Task ExecuteAndTransformAsync_should_transform_content_with_old_content() + public async Task TransformAsync_should_transform_content_with_old_content() { var content = new NamedContentData() @@ -357,7 +364,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting replace(ctx.data); "; - var result = await sut.ExecuteAndTransformAsync(context, script); + var result = await sut.TransformAsync(context, script, contentOptions); Assert.Equal(expected, result); } @@ -374,7 +381,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = new { i = 2 } }; - var result = sut.Evaluate(context, script); + var result = ((IScriptEngine)sut).Evaluate(context, script); Assert.True(result); } @@ -391,7 +398,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = new { status = Status.Published } }; - var result = sut.Evaluate(context, script); + var result = ((IScriptEngine)sut).Evaluate(context, script); Assert.True(result); } @@ -408,7 +415,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = new { i = 2 } }; - var result = sut.Evaluate(context, script); + var result = ((IScriptEngine)sut).Evaluate(context, script); Assert.False(result); } @@ -425,7 +432,7 @@ namespace Squidex.Domain.Apps.Core.Operations.Scripting ["value"] = new { i = 2 } }; - var result = sut.Evaluate(context, script); + var result = ((IScriptEngine)sut).Evaluate(context, script); Assert.False(result); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs index 54fb3ad16..14d37bc2c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs @@ -32,10 +32,10 @@ namespace Squidex.Domain.Apps.Entities.Assets public AssetChangedTriggerHandlerTests() { - A.CallTo(() => scriptEngine.Evaluate(A._, "true")) + A.CallTo(() => scriptEngine.Evaluate(A._, "true", default)) .Returns(true); - A.CallTo(() => scriptEngine.Evaluate(A._, "false")) + A.CallTo(() => scriptEngine.Evaluate(A._, "false", default)) .Returns(false); sut = new AssetChangedTriggerHandler(scriptEngine, assetLoader); @@ -149,12 +149,12 @@ namespace Squidex.Domain.Apps.Entities.Assets if (string.IsNullOrWhiteSpace(condition)) { - A.CallTo(() => scriptEngine.Evaluate(A._, condition)) + A.CallTo(() => scriptEngine.Evaluate(A._, condition, default)) .MustNotHaveHappened(); } else { - A.CallTo(() => scriptEngine.Evaluate(A._, condition)) + A.CallTo(() => scriptEngine.Evaluate(A._, condition, default)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs index 1ce72b4a8..addf2f834 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentTriggerHandlerTests.cs @@ -33,10 +33,10 @@ namespace Squidex.Domain.Apps.Entities.Comments public CommentTriggerHandlerTests() { - A.CallTo(() => scriptEngine.Evaluate(A._, "true")) + A.CallTo(() => scriptEngine.Evaluate(A._, "true", default)) .Returns(true); - A.CallTo(() => scriptEngine.Evaluate(A._, "false")) + A.CallTo(() => scriptEngine.Evaluate(A._, "false", default)) .Returns(false); sut = new CommentTriggerHandler(scriptEngine, userResolver); @@ -290,12 +290,12 @@ namespace Squidex.Domain.Apps.Entities.Comments if (string.IsNullOrWhiteSpace(condition)) { - A.CallTo(() => scriptEngine.Evaluate(A._, condition)) + A.CallTo(() => scriptEngine.Evaluate(A._, condition, default)) .MustNotHaveHappened(); } else { - A.CallTo(() => scriptEngine.Evaluate(A._, condition)) + A.CallTo(() => scriptEngine.Evaluate(A._, condition, default)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs index f87f3fa57..85cf72960 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs @@ -41,10 +41,10 @@ namespace Squidex.Domain.Apps.Entities.Contents public ContentChangedTriggerHandlerTests() { - A.CallTo(() => scriptEngine.Evaluate(A._, "true")) + A.CallTo(() => scriptEngine.Evaluate(A._, "true", default)) .Returns(true); - A.CallTo(() => scriptEngine.Evaluate(A._, "false")) + A.CallTo(() => scriptEngine.Evaluate(A._, "false", default)) .Returns(false); sut = new ContentChangedTriggerHandler(scriptEngine, contentLoader); @@ -251,12 +251,12 @@ namespace Squidex.Domain.Apps.Entities.Contents if (string.IsNullOrWhiteSpace(condition)) { - A.CallTo(() => scriptEngine.Evaluate(A._, A._)) + A.CallTo(() => scriptEngine.Evaluate(A._, A._, default)) .MustNotHaveHappened(); } else { - A.CallTo(() => scriptEngine.Evaluate(A._, condition)) + A.CallTo(() => scriptEngine.Evaluate(A._, condition, default)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs index d6d328f31..24d54dc09 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs @@ -100,7 +100,7 @@ namespace Squidex.Domain.Apps.Entities.Contents A.CallTo(() => appProvider.GetAppWithSchemaAsync(AppId, SchemaId)) .Returns((app, schema)); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(A._, A._)) + A.CallTo(() => scriptEngine.TransformAsync(A._, A._, ScriptOptions())) .ReturnsLazily(x => Task.FromResult(x.GetArgument(0)!.Data!)); patched = patch.MergeInto(data); @@ -137,9 +137,9 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft }) ); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(ScriptContext(data, null, Status.Draft), "")) + A.CallTo(() => scriptEngine.TransformAsync(ScriptContext(data, null, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "")) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions())) .MustNotHaveHappened(); } @@ -160,9 +160,9 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentStatusChanged { Status = Status.Published, Change = StatusChange.Published }) ); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(ScriptContext(data, null, Status.Draft), "")) + A.CallTo(() => scriptEngine.TransformAsync(ScriptContext(data, null, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); - A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Published), "")) + A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Published), "", ScriptOptions())) .MustHaveHappened(); } @@ -192,7 +192,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentUpdated { Data = otherData }) ); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(ScriptContext(otherData, data, Status.Draft), "")) + A.CallTo(() => scriptEngine.TransformAsync(ScriptContext(otherData, data, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -216,7 +216,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentUpdated { Data = otherData }) ); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(ScriptContext(otherData, data, Status.Draft), "")) + A.CallTo(() => scriptEngine.TransformAsync(ScriptContext(otherData, data, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -233,7 +233,7 @@ namespace Squidex.Domain.Apps.Entities.Contents Assert.Single(LastEvents); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(A._, "")) + A.CallTo(() => scriptEngine.TransformAsync(A._, "", ScriptOptions())) .MustNotHaveHappened(); } @@ -265,7 +265,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentUpdated { Data = patched }) ); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(ScriptContext(patched, data, Status.Draft), "")) + A.CallTo(() => scriptEngine.TransformAsync(ScriptContext(patched, data, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -289,7 +289,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentUpdated { Data = patched }) ); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(ScriptContext(patched, data, Status.Draft), "")) + A.CallTo(() => scriptEngine.TransformAsync(ScriptContext(patched, data, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -306,7 +306,7 @@ namespace Squidex.Domain.Apps.Entities.Contents Assert.Single(LastEvents); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(A._, "")) + A.CallTo(() => scriptEngine.TransformAsync(A._, "", ScriptOptions())) .MustNotHaveHappened(); } @@ -328,7 +328,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentStatusChanged { Status = Status.Published, Change = StatusChange.Published }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Published, Status.Draft), "")) + A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Published, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -350,7 +350,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Archived, Status.Draft), "")) + A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Archived, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -373,7 +373,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentStatusChanged { Status = Status.Draft, Change = StatusChange.Unpublished }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Draft, Status.Published), "")) + A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Draft, Status.Published), "", ScriptOptions())) .MustHaveHappened(); } @@ -397,7 +397,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentStatusChanged { Change = StatusChange.Change, Status = Status.Archived }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Archived, Status.Draft), "")) + A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Archived, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -424,7 +424,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentStatusScheduled { Status = Status.Published, DueTime = dueTime }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "")) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions())) .MustNotHaveHappened(); } @@ -452,7 +452,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "")) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions())) .MustHaveHappened(); } @@ -480,7 +480,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentSchedulingCancelled()) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "")) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions())) .MustNotHaveHappened(); } @@ -502,7 +502,7 @@ namespace Squidex.Domain.Apps.Entities.Contents CreateContentEvent(new ContentDeleted()) ); - A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Draft), "")) + A.CallTo(() => scriptEngine.ExecuteAsync(ScriptContext(data, null, Status.Draft), "", ScriptOptions())) .MustHaveHappened(); } @@ -587,6 +587,11 @@ namespace Squidex.Domain.Apps.Entities.Contents return A.That.Matches(x => M(x, newData, oldData, newStatus, oldStatus)); } + private ScriptOptions ScriptOptions() + { + return A.That.Matches(x => x.CanDisallow && x.CanReject && x.AsContext); + } + private bool M(ScriptVars x, NamedContentData? newData, NamedContentData? oldData, Status newStatus, Status oldStatus) { return diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs index 2409b7d7a..3e57db153 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs @@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Counter ["appId"] = appId }; - var result = sut.Interpolate(context, script); + var result = sut.Execute(context, script).ToString(); Assert.Equal("3", result); } @@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Counter ["appId"] = appId }; - var result = sut.Interpolate(context, script); + var result = sut.Execute(context, script).ToString(); Assert.Equal("3", result); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs index 62680f6ae..9dc4b3c90 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs @@ -67,7 +67,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries await sut.EnrichAsync(ctx, new[] { content }, schemaProvider); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(A._, A._)) + A.CallTo(() => scriptEngine.TransformAsync(A._, A._, default)) .MustNotHaveHappened(); } @@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries await sut.EnrichAsync(ctx, new[] { content }, schemaProvider); - A.CallTo(() => scriptEngine.ExecuteAndTransformAsync(A._, A._)) + A.CallTo(() => scriptEngine.TransformAsync(A._, A._, default)) .MustNotHaveHappened(); } @@ -93,7 +93,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries var content = new ContentEntity { SchemaId = schemaWithScriptId, Data = oldData }; - A.CallTo(() => scriptEngine.TransformAsync(A._, "my-query")) + A.CallTo(() => scriptEngine.TransformAsync(A._, "my-query", default)) .Returns(new NamedContentData()); await sut.EnrichAsync(ctx, new[] { content }, schemaProvider); @@ -105,7 +105,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries ReferenceEquals(x.User, ctx.User) && ReferenceEquals(x.Data, oldData) && x.ContentId == content.Id), - "my-query")) + "my-query", + A._)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs index 1d806ac83..a3715157d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemaChangedTriggerHandlerTests.cs @@ -31,10 +31,10 @@ namespace Squidex.Domain.Apps.Entities.Schemas public SchemaChangedTriggerHandlerTests() { - A.CallTo(() => scriptEngine.Evaluate(A._, "true")) + A.CallTo(() => scriptEngine.Evaluate(A._, "true", default)) .Returns(true); - A.CallTo(() => scriptEngine.Evaluate(A._, "false")) + A.CallTo(() => scriptEngine.Evaluate(A._, "false", default)) .Returns(false); sut = new SchemaChangedTriggerHandler(scriptEngine); @@ -136,12 +136,12 @@ namespace Squidex.Domain.Apps.Entities.Schemas if (string.IsNullOrWhiteSpace(condition)) { - A.CallTo(() => scriptEngine.Evaluate(A._, condition)) + A.CallTo(() => scriptEngine.Evaluate(A._, condition, default)) .MustNotHaveHappened(); } else { - A.CallTo(() => scriptEngine.Evaluate(A._, condition)) + A.CallTo(() => scriptEngine.Evaluate(A._, condition, default)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs index 0f04ede63..41ab8c11a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs @@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Search result.Should().BeEquivalentTo(result2); - A.CallTo(() => log.Log(A._, A._, A._, A>._!)) + A.CallTo(() => log.Log(A._, A._, A._, A>._!)) .MustHaveHappened(); } }