Browse Source

Scripting extensions (#1141)

* Custom indexes.

* Adjust test.

* Improve json body handling.

* Just some formatting.
pull/1144/head
Sebastian Stehle 2 years ago
committed by GitHub
parent
commit
fb1ebf83ce
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 62
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs
  2. 32
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs
  3. 2
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs
  4. 4
      frontend/src/app/theme/_forms.scss

62
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Extensions/HttpJintExtension.cs

@ -9,6 +9,7 @@ using System.Text;
using Jint; using Jint;
using Jint.Native; using Jint.Native;
using Jint.Native.Json; using Jint.Native.Json;
using Jint.Native.Object;
using Jint.Runtime; using Jint.Runtime;
using Squidex.Domain.Apps.Core.Properties; using Squidex.Domain.Apps.Core.Properties;
using Squidex.Infrastructure; using Squidex.Infrastructure;
@ -18,7 +19,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions;
public sealed class HttpJintExtension : IJintExtension, IScriptDescriptor public sealed class HttpJintExtension : IJintExtension, IScriptDescriptor
{ {
private delegate void HttpJsonDelegate(string url, Action<JsValue> callback, JsValue? headers = null, bool ignoreError = false); private delegate void HttpJsonDelegate(string url, Action<JsValue> callback, JsValue? headers = null, bool ignoreError = false);
private delegate void HttpJsonWithBodyDelegate(string url, JsValue post, Action<JsValue> callback, JsValue? headers = null, bool ignoreError = false); private delegate void HttpJsonWithBodyDelegate(string url, JsValue body, Action<JsValue> callback, JsValue? headers = null, bool ignoreError = false);
private readonly IHttpClientFactory httpClientFactory; private readonly IHttpClientFactory httpClientFactory;
public HttpJintExtension(IHttpClientFactory httpClientFactory) public HttpJintExtension(IHttpClientFactory httpClientFactory)
@ -113,34 +114,47 @@ public sealed class HttpJintExtension : IJintExtension, IScriptDescriptor
}); });
} }
private static HttpRequestMessage CreateRequest(ScriptExecutionContext context, HttpMethod method, Uri uri, JsValue? body, JsValue? headers) private static HttpRequestMessage CreateRequest(ScriptExecutionContext context,
HttpMethod method,
Uri uri,
JsValue? body,
JsValue? headers)
{ {
var request = new HttpRequestMessage(method, uri); var request = new HttpRequestMessage(method, uri);
if (body != null) var contentType = string.Empty;
foreach (var (name, value) in GetNonEmptyProperties(headers))
{ {
var jsonWriter = new JsonSerializer(context.Engine); request.Headers.TryAddWithoutValidation(name, value ?? string.Empty);
var jsonContent = jsonWriter.Serialize(body, JsValue.Undefined, JsValue.Undefined)?.ToString();
if (jsonContent != null) if (string.Equals(name, "Content-Type", StringComparison.OrdinalIgnoreCase))
{ {
request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json"); contentType = value ?? string.Empty;
} }
} }
if (headers != null && headers.Type == Types.Object) if (body != null)
{ {
var obj = headers.AsObject(); if (string.Equals(contentType, "application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
foreach (var (key, property) in obj.GetOwnProperties())
{ {
var value = TypeConverter.ToString(property.Value); var formValues = new List<KeyValuePair<string, string>>();
foreach (var (name, value) in GetNonEmptyProperties(body))
{
formValues.Add(new (name, value));
}
var keyString = key.AsString(); request.Content = new FormUrlEncodedContent(formValues);
}
else
{
var jsonWriter = new JsonSerializer(context.Engine);
var jsonContent = jsonWriter.Serialize(body, JsValue.Undefined, JsValue.Undefined)?.ToString();
if (!string.IsNullOrWhiteSpace(keyString)) if (jsonContent != null)
{ {
request.Headers.TryAddWithoutValidation(keyString, value ?? string.Empty); request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
} }
} }
} }
@ -185,4 +199,22 @@ public sealed class HttpJintExtension : IJintExtension, IScriptDescriptor
describe(JsonType.Function, "deleteJSON(url, callback, headers?, ignoreError?)", describe(JsonType.Function, "deleteJSON(url, callback, headers?, ignoreError?)",
Resources.ScriptingDeleteJson); Resources.ScriptingDeleteJson);
} }
private static IEnumerable<(string, string)> GetNonEmptyProperties(JsValue? source)
{
if (source?.IsObject() != true || source.AsObject() is not ObjectInstance obj)
{
yield break;
}
foreach (var (key, property) in obj.GetOwnProperties())
{
if (key.ToString() is string name && !string.IsNullOrWhiteSpace(name))
{
var value = TypeConverter.ToString(property.Value) ?? string.Empty;
yield return (name, value);
}
}
}
} }

32
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineHelperTests.cs

@ -586,6 +586,38 @@ public class JintScriptEngineHelperTests : IClassFixture<TranslationsFixture>
Assert.Equal(expectedResult, actual); Assert.Equal(expectedResult, actual);
} }
[Fact]
public async Task Should_make_postJson_as_form_values()
{
var httpHandler = SetupRequest();
var vars = new ScriptVars
{
};
const string script = @"
var url = 'http://squidex.io';
var body = { key: 42 };
postJSON(url, body, function(actual) {
complete(actual);
}, {
'Content-Type': 'application/x-www-form-urlencoded'
});
";
var actual = await sut.ExecuteAsync(vars, script);
httpHandler.ShouldBeMethod(HttpMethod.Post);
httpHandler.ShouldBeUrl("http://squidex.io/");
httpHandler.ShouldBeBody("key=42", "application/x-www-form-urlencoded");
var expectedResult = JsonValue.Object().Add("key", 42);
Assert.Equal(expectedResult, actual);
}
[Fact] [Fact]
public async Task Should_make_putJson_request() public async Task Should_make_putJson_request()
{ {

2
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/MockupHttpHandler.cs

@ -47,7 +47,7 @@ internal sealed class MockupHttpHandler : HttpMessageHandler
currentRequest = request; currentRequest = request;
if (request.Content is StringContent body) if (request.Content is HttpContent body)
{ {
currentContent = await body.ReadAsStringAsync(cancellationToken); currentContent = await body.ReadAsStringAsync(cancellationToken);
currentContentType = body.Headers.ContentType?.MediaType; currentContentType = body.Headers.ContentType?.MediaType;

4
frontend/src/app/theme/_forms.scss

@ -114,6 +114,10 @@
ul { ul {
margin: 0; margin: 0;
} }
li {
word-wrap: break-word;
}
} }
.form-bubble { .form-bubble {

Loading…
Cancel
Save