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.Native;
using Jint.Native.Json;
using Jint.Native.Object;
using Jint.Runtime;
using Squidex.Domain.Apps.Core.Properties;
using Squidex.Infrastructure;
@ -18,7 +19,7 @@ namespace Squidex.Domain.Apps.Core.Scripting.Extensions;
public sealed class HttpJintExtension : IJintExtension, IScriptDescriptor
{
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;
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);
if (body != null)
var contentType = string.Empty;
foreach (var (name, value) in GetNonEmptyProperties(headers))
{
var jsonWriter = new JsonSerializer(context.Engine);
var jsonContent = jsonWriter.Serialize(body, JsValue.Undefined, JsValue.Undefined)?.ToString();
request.Headers.TryAddWithoutValidation(name, value ?? string.Empty);
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();
foreach (var (key, property) in obj.GetOwnProperties())
if (string.Equals(contentType, "application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
{
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?)",
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);
}
[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]
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;
if (request.Content is StringContent body)
if (request.Content is HttpContent body)
{
currentContent = await body.ReadAsStringAsync(cancellationToken);
currentContentType = body.Headers.ContentType?.MediaType;

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

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

Loading…
Cancel
Save