diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs index 4ad092638..ada1f5adf 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs @@ -13,6 +13,7 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Core.ConvertContent @@ -28,32 +29,35 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return field.IsForApi() ? data : null; }; - public static readonly FieldConverter ExcludeChangedTypes = (data, field) => + public static FieldConverter ExcludeChangedTypes(IJsonSerializer jsonSerializer) { - foreach (var value in data.Values) + return (data, field) => { - if (value.Type == JsonValueType.Null) + foreach (var value in data.Values) { - continue; - } + if (value.Type == JsonValueType.Null) + { + continue; + } - try - { - var (_, error) = JsonValueConverter.ConvertValue(field, value); + try + { + var (_, error) = JsonValueConverter.ConvertValue(field, value, jsonSerializer); - if (error != null) + if (error != null) + { + return null; + } + } + catch { return null; } } - catch - { - return null; - } - } - return data; - }; + return data; + }; + } public static FieldConverter ResolveInvariant(LanguagesConfig languages) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs index fe4dc2c45..c68bf429e 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ValueConverters.cs @@ -28,29 +28,32 @@ namespace Squidex.Domain.Apps.Core.ConvertContent return field.IsForApi() ? value : null; }; - public static readonly ValueConverter ExcludeChangedTypes = (value, field, parent) => + public static ValueConverter ExcludeChangedTypes(IJsonSerializer jsonSerializer) { - if (value.Type == JsonValueType.Null) + return (value, field, parent) => { - return value; - } + if (value.Type == JsonValueType.Null) + { + return value; + } - try - { - var (_, error) = JsonValueConverter.ConvertValue(field, value); + try + { + var (_, error) = JsonValueConverter.ConvertValue(field, value, jsonSerializer); - if (error != null) + if (error != null) + { + return null; + } + } + catch { return null; } - } - catch - { - return null; - } - return value; - }; + return value; + }; + } public static ValueConverter DecodeJson(IJsonSerializer jsonSerializer) { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj b/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj index 1021e1b9b..94276a57f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj @@ -18,6 +18,7 @@ + diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs index b6e188968..0983e722f 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs @@ -5,11 +5,14 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Collections.Generic; +using System.IO; +using GeoJSON.Net; +using GeoJSON.Net.Geometry; using NodaTime.Text; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Translations; using Squidex.Infrastructure.Validation; @@ -23,10 +26,13 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public readonly struct Args { public readonly IJsonValue Value; + public readonly IJsonSerializer JsonSerializer; - public Args(IJsonValue value) + public Args(IJsonValue value, IJsonSerializer jsonSerializer) { Value = value; + + JsonSerializer = jsonSerializer; } } @@ -34,12 +40,14 @@ namespace Squidex.Domain.Apps.Core.ValidateContent { } - public static (object? Result, JsonError? Error) ConvertValue(IField field, IJsonValue value) + public static (object? Result, JsonError? Error) ConvertValue(IField field, IJsonValue value, IJsonSerializer jsonSerializer) { Guard.NotNull(field, nameof(field)); Guard.NotNull(value, nameof(value)); - return field.Accept(Instance, new Args(value)); + var args = new Args(value, jsonSerializer); + + return field.Accept(Instance, args); } public (object? Result, JsonError? Error) Visit(IArrayField field, Args args) @@ -116,46 +124,55 @@ namespace Squidex.Domain.Apps.Core.ValidateContent public (object? Result, JsonError? Error) Visit(IField field, Args args) { - if (args.Value is JsonObject geolocation) + if (args.Value is JsonObject geoObject) { - foreach (var propertyName in geolocation.Keys) + try { - if (!string.Equals(propertyName, "latitude", StringComparison.OrdinalIgnoreCase) && - !string.Equals(propertyName, "longitude", StringComparison.OrdinalIgnoreCase)) + using (var stream = new MemoryStream()) { - return (null, new JsonError(T.Get("contents.invalidGeolocationMoreProperties"))); + args.JsonSerializer.Serialize(args.Value, stream, true); + + stream.Position = 0; + + var geoJson = args.JsonSerializer.Deserialize(stream); + + return (geoJson, null); } } - - if (geolocation.TryGetValue("latitude", out var latValue) && latValue is JsonNumber latNumber) + catch { - var lat = latNumber.Value; + if (geoObject.TryGetValue("latitude", out var latValue) && latValue is JsonNumber latNumber) + { + var lat = latNumber.Value; - if (!lat.IsBetween(-90, 90)) + if (!lat.IsBetween(-90, 90)) + { + return (null, new JsonError(T.Get("contents.invalidGeolocationLatitude"))); + } + } + else { - return (null, new JsonError(T.Get("contents.invalidGeolocationLatitude"))); + return (null, new JsonError(T.Get("contents.invalidGeolocation"))); } - } - else - { - return (null, new JsonError(T.Get("contents.invalidGeolocation"))); - } - if (geolocation.TryGetValue("longitude", out var lonValue) && lonValue is JsonNumber lonNumber) - { - var lon = lonNumber.Value; + if (geoObject.TryGetValue("longitude", out var lonValue) && lonValue is JsonNumber lonNumber) + { + var lon = lonNumber.Value; - if (!lon.IsBetween(-180, 180)) + if (!lon.IsBetween(-180, 180)) + { + return (null, new JsonError(T.Get("contents.invalidGeolocationLongitude"))); + } + } + else { - return (null, new JsonError(T.Get("contents.invalidGeolocationLongitude"))); + return (null, new JsonError(T.Get("contents.invalidGeolocation"))); } - } - else - { - return (null, new JsonError(T.Get("contents.invalidGeolocation"))); - } - return (args.Value, null); + var position = new Position(latNumber.Value, lonNumber.Value); + + return (position, null); + } } return (null, new JsonError(T.Get("contents.invalidGeolocation"))); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs index 7a611e19e..a58fb6c25 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Immutable; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json; namespace Squidex.Domain.Apps.Core.ValidateContent { @@ -16,17 +17,21 @@ namespace Squidex.Domain.Apps.Core.ValidateContent { public ImmutableQueue Path { get; private set; } = ImmutableQueue.Empty; + public IJsonSerializer JsonSerializer { get; private set; } + public DomainId ContentId { get; } public bool IsOptional { get; private set; } public ValidationContext( + IJsonSerializer jsonSerializer, NamedId appId, NamedId schemaId, Schema schema, DomainId contentId) : base(appId, schemaId, schema) { + JsonSerializer = jsonSerializer; ContentId = contentId; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs index 091fef4eb..efab6fd81 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs @@ -41,7 +41,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators } else { - var (json, error) = JsonValueConverter.ConvertValue(field, jsonValue); + var (json, error) = JsonValueConverter.ConvertValue(field, jsonValue, context.JsonSerializer); if (error != null) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentOperationContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentOperationContext.cs index 9f488d048..586b64089 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentOperationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentOperationContext.cs @@ -20,6 +20,7 @@ using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Validation; using Squidex.Log; @@ -40,6 +41,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject private readonly IEnumerable validators; private readonly IContentWorkflow contentWorkflow; private readonly IContentRepository contentRepository; + private readonly IJsonSerializer jsonSerializer; private ISchemaEntity schema; private IAppEntity app; private ContentCommand command; @@ -54,6 +56,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject IEnumerable validators, IContentWorkflow contentWorkflow, IContentRepository contentRepository, + IJsonSerializer jsonSerializer, IScriptEngine scriptEngine, ISemanticLog log) { @@ -61,6 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject Guard.NotDefault(validators, nameof(validators)); Guard.NotDefault(contentWorkflow, nameof(contentWorkflow)); Guard.NotDefault(contentRepository, nameof(contentRepository)); + Guard.NotDefault(jsonSerializer, nameof(jsonSerializer)); Guard.NotDefault(scriptEngine, nameof(scriptEngine)); Guard.NotDefault(log, nameof(log)); @@ -68,6 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject this.validators = validators; this.contentWorkflow = contentWorkflow; this.contentRepository = contentRepository; + this.jsonSerializer = jsonSerializer; this.scriptEngine = scriptEngine; this.log = log; @@ -98,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject this.schema = schema; - validationContext = new ValidationContext(appId, schemaId, schema.SchemaDef, command.ContentId).Optimized(optimized); + validationContext = new ValidationContext(jsonSerializer, appId, schemaId, schema.SchemaDef, command.ContentId).Optimized(optimized); } public Task GetInitialStatusAsync() diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs index 1cef99ef9..d5a5dd98d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs @@ -15,6 +15,7 @@ using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Tasks; namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps @@ -24,16 +25,28 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps private readonly IUrlGenerator urlGenerator; private readonly IAssetRepository assetRepository; private readonly IContentRepository contentRepository; + private readonly FieldConverter excludedChangedField; + private readonly FieldConverter excludedChangedValue; + private readonly FieldConverter excludedHiddenField; + private readonly FieldConverter excludedHiddenValue; - public ConvertData(IUrlGenerator urlGenerator, IAssetRepository assetRepository, IContentRepository contentRepository) + public ConvertData(IUrlGenerator urlGenerator, IJsonSerializer jsonSerializer, + IAssetRepository assetRepository, IContentRepository contentRepository) { Guard.NotNull(urlGenerator, nameof(urlGenerator)); + Guard.NotNull(jsonSerializer, nameof(jsonSerializer)); Guard.NotNull(assetRepository, nameof(assetRepository)); Guard.NotNull(contentRepository, nameof(contentRepository)); this.urlGenerator = urlGenerator; this.assetRepository = assetRepository; this.contentRepository = contentRepository; + + excludedChangedField = FieldConverters.ExcludeChangedTypes(jsonSerializer); + excludedChangedValue = FieldConverters.ForValues(ValueConverters.ForNested(ValueConverters.ExcludeChangedTypes(jsonSerializer))); + + excludedHiddenField = FieldConverters.ExcludeHidden; + excludedHiddenValue = FieldConverters.ForValues(ValueConverters.ForNested(ValueConverters.ExcludeHidden)); } public async Task EnrichAsync(Context context, IEnumerable contents, ProvideSchema schemas) @@ -102,12 +115,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries.Steps { if (!context.IsFrontendClient) { - yield return FieldConverters.ExcludeHidden; - yield return FieldConverters.ForValues(ValueConverters.ForNested(ValueConverters.ExcludeHidden)); + yield return excludedHiddenField; + yield return excludedHiddenValue; } - yield return FieldConverters.ExcludeChangedTypes; - yield return FieldConverters.ForValues(ValueConverters.ForNested(ValueConverters.ExcludeChangedTypes)); + yield return excludedChangedField; + yield return excludedChangedValue; if (cleanReferences != null) { diff --git a/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs b/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs index 703551399..15586f24a 100644 --- a/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs +++ b/backend/src/Squidex.Infrastructure/Json/IJsonSerializer.cs @@ -14,7 +14,7 @@ namespace Squidex.Infrastructure.Json { string Serialize(T value, bool intented = false); - void Serialize(T value, Stream stream); + void Serialize(T value, Stream stream, bool leaveOpen = false); T Deserialize(string value, Type? actualType = null); diff --git a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs index 3e70cf92b..055dea798 100644 --- a/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs +++ b/backend/src/Squidex.Infrastructure/Json/Newtonsoft/NewtonsoftJsonSerializer.cs @@ -30,9 +30,9 @@ namespace Squidex.Infrastructure.Json.Newtonsoft return JsonConvert.SerializeObject(value, intented ? Formatting.Indented : Formatting.None, settings); } - public void Serialize(T value, Stream stream) + public void Serialize(T value, Stream stream, bool leaveOpen = false) { - using (var writer = new StreamWriter(stream)) + using (var writer = new StreamWriter(stream, leaveOpen: leaveOpen)) { serializer.Serialize(writer, value); diff --git a/backend/src/Squidex/Config/Domain/SerializationServices.cs b/backend/src/Squidex/Config/Domain/SerializationServices.cs index 86b821497..1e907087c 100644 --- a/backend/src/Squidex/Config/Domain/SerializationServices.cs +++ b/backend/src/Squidex/Config/Domain/SerializationServices.cs @@ -5,6 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using GeoJSON.Net.Converters; using Microsoft.Extensions.DependencyInjection; using Migrations; using Newtonsoft.Json; @@ -40,6 +41,7 @@ namespace Squidex.Config.Domain new EnvelopeHeadersConverter(), new FilterConverter(), new InstantConverter(), + new GeoJsonConverter(), new JsonValueConverter(), new LanguageConverter(), new LanguagesConfigConverter(), diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs index 2dfc970a7..f93d48086 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/FieldConvertersTests.cs @@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddValue("en", null) .AddValue("de", 1); - var result = FieldConverters.ExcludeChangedTypes(source, field); + var result = FieldConverters.ExcludeChangedTypes(TestUtils.DefaultSerializer)(source, field); Assert.Same(source, result); } @@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent .AddValue("en", "EN") .AddValue("de", 0); - var result = FieldConverters.ExcludeChangedTypes(source, field); + var result = FieldConverters.ExcludeChangedTypes(TestUtils.DefaultSerializer)(source, field); Assert.Null(result); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs index 808313c2f..cc4d30983 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/ValueConvertersTests.cs @@ -106,7 +106,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ConvertContent { var source = JsonValue.Create("invalid"); - var result = ValueConverters.ExcludeChangedTypes(source, numberField); + var result = ValueConverters.ExcludeChangedTypes(TestUtils.DefaultSerializer)(source, numberField); Assert.Null(result); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs index 1737ab066..05f67766b 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs @@ -38,13 +38,17 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent } [Fact] - public async Task Should_not_add_error_if_geolocation_is_valid() + public async Task Should_not_add_error_if_geolocation_is_valid_geojson() { var sut = Field(new GeolocationFieldProperties()); var geolocation = JsonValue.Object() - .Add("latitude", 0) - .Add("longitude", 0); + .Add("coordinates", + JsonValue.Array( + JsonValue.Create(12), + JsonValue.Create(45) + )) + .Add("type", "Point"); await sut.ValidateAsync(geolocation, errors); @@ -52,49 +56,35 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent } [Fact] - public async Task Should_add_error_if_geolocation_has_invalid_latitude() + public async Task Should_not_add_error_if_geolocation_is_valid() { - var sut = Field(new GeolocationFieldProperties { IsRequired = true }); + var sut = Field(new GeolocationFieldProperties()); - var geolocation = JsonValue.Object() - .Add("latitude", 200) - .Add("longitude", 0); + await sut.ValidateAsync(CreateValue(0, 0), errors); - await sut.ValidateAsync(geolocation, errors); - - errors.Should().BeEquivalentTo( - new[] { "Latitude must be between -90 and 90." }); + Assert.Empty(errors); } [Fact] - public async Task Should_add_error_if_geolocation_has_invalid_longitude() + public async Task Should_add_error_if_geolocation_has_invalid_latitude() { var sut = Field(new GeolocationFieldProperties { IsRequired = true }); - var geolocation = JsonValue.Object() - .Add("latitude", 0) - .Add("longitude", 200); - - await sut.ValidateAsync(geolocation, errors); + await sut.ValidateAsync(CreateValue(200, 0), errors); errors.Should().BeEquivalentTo( - new[] { "Longitude must be between -180 and 180." }); + new[] { "Latitude must be between -90 and 90." }); } [Fact] - public async Task Should_add_error_if_geolocation_has_too_many_properties() + public async Task Should_add_error_if_geolocation_has_invalid_longitude() { var sut = Field(new GeolocationFieldProperties { IsRequired = true }); - var geolocation = JsonValue.Object() - .Add("invalid", 0) - .Add("latitude", 0) - .Add("longitude", 0); - - await sut.ValidateAsync(geolocation, errors); + await sut.ValidateAsync(CreateValue(0, 200), errors); errors.Should().BeEquivalentTo( - new[] { "Geolocation can only have latitude and longitude property." }); + new[] { "Longitude must be between -180 and 180." }); } [Fact] @@ -108,6 +98,11 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent new[] { "Field is required." }); } + private static JsonObject CreateValue(double lat, double lon) + { + return JsonValue.Object().Add("latitude", lat).Add("longitude", lon); + } + private static RootField Field(GeolocationFieldProperties properties) { return Fields.Geolocation(1, "my-geolocation", Partitioning.Invariant, properties); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs index fb8c064e6..809e364e4 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Core.ValidateContent.Validators; using Squidex.Infrastructure; @@ -127,6 +128,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent ValidationAction action = ValidationAction.Upsert) { var context = new ValidationContext( + TestUtils.DefaultSerializer, AppId, SchemaId, schema ?? new Schema(SchemaId.Name), diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs index 10a4820b9..309818efc 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/TestUtils.cs @@ -8,6 +8,7 @@ using System; using System.Linq; using System.Reflection; +using GeoJSON.Net.Converters; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Squidex.Domain.Apps.Core.Apps.Json; @@ -30,7 +31,9 @@ namespace Squidex.Domain.Apps.Core.TestHelpers { public static readonly IJsonSerializer DefaultSerializer = CreateSerializer(); - public static IJsonSerializer CreateSerializer(TypeNameHandling typeNameHandling = TypeNameHandling.Auto) + public static readonly JsonSerializerSettings DefaultSerializerSettings = CreateSerializerSettings(); + + public static JsonSerializerSettings CreateSerializerSettings(TypeNameHandling typeNameHandling = TypeNameHandling.Auto) { var typeNameRegistry = new TypeNameRegistry() @@ -51,6 +54,7 @@ namespace Squidex.Domain.Apps.Core.TestHelpers new DomainIdConverter(), new EnvelopeHeadersConverter(), new FilterConverter(), + new GeoJsonConverter(), new InstantConverter(), new JsonValueConverter(), new LanguageConverter(), @@ -73,6 +77,13 @@ namespace Squidex.Domain.Apps.Core.TestHelpers TypeNameHandling = typeNameHandling }; + return serializerSettings; + } + + public static IJsonSerializer CreateSerializer(TypeNameHandling typeNameHandling = TypeNameHandling.Auto) + { + var serializerSettings = CreateSerializerSettings(typeNameHandling); + return new NewtonsoftJsonSerializer(serializerSettings); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs index d44d5cbd2..8605ec960 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/MongoDb/AssetsQueryFixture.cs @@ -12,6 +12,7 @@ using MongoDB.Bson; using MongoDB.Driver; using Newtonsoft.Json; using Squidex.Domain.Apps.Core.Assets; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.MongoDb.Assets; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -117,7 +118,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.MongoDb private static void SetupJson() { - var jsonSerializer = JsonSerializer.Create(JsonHelper.DefaultSettings()); + var jsonSerializer = JsonSerializer.Create(TestUtils.DefaultSerializerSettings); BsonJsonConvention.Register(jsonSerializer); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs index 76b16c63d..1496a6303 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Domain.Apps.Core.Tags; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Caching; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs index 5ac172da2..b7b92e172 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using FakeItEasy; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core.Tags; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; @@ -30,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.Queries var options = Options.Create(new AssetOptions { DefaultPageSize = 30 }); - sut = new AssetQueryParser(JsonHelper.DefaultSerializer, tagService, options); + sut = new AssetQueryParser(TestUtils.DefaultSerializer, tagService, options); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs index da27d4d3f..48dd2b747 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using FakeItEasy; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Shared.Users; 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 78afca71b..a4180af62 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs @@ -17,6 +17,7 @@ using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.Rules.EnrichedEvents; using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.Scripting; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs index 5cac56b0c..b35ca5602 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs @@ -13,6 +13,7 @@ using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Scripting; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents.Commands; @@ -107,10 +108,12 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject var validators = Enumerable.Repeat(new DefaultValidatorsFactory(), 1); - var context = new ContentOperationContext(appProvider, + var context = new ContentOperationContext( + appProvider, validators, contentWorkflow, contentRepository, + TestUtils.DefaultSerializer, scriptEngine, A.Fake()); sut = new ContentDomainObject(Store, A.Dummy(), context); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs index aeb95db32..31d321f37 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs @@ -16,6 +16,7 @@ using Newtonsoft.Json; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.Contents.Text; @@ -63,7 +64,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb mongoDatabase, CreateAppProvider(), CreateTextIndexer(), - JsonHelper.DefaultSerializer); + TestUtils.DefaultSerializer); Task.Run(async () => { @@ -161,7 +162,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.MongoDb private static void SetupJson() { - var jsonSerializer = JsonSerializer.Create(JsonHelper.DefaultSettings()); + var jsonSerializer = JsonSerializer.Create(TestUtils.DefaultSerializerSettings); BsonJsonConvention.Register(jsonSerializer); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs index 67549c7b6..be1ec0690 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs @@ -10,6 +10,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; @@ -42,7 +43,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries var cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); - sut = new ContentQueryParser(cache, JsonHelper.DefaultSerializer, options); + sut = new ContentQueryParser(cache, TestUtils.DefaultSerializer, options); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs index 19c790b7b..d02e451a7 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs @@ -12,6 +12,7 @@ using FakeItEasy; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; using Squidex.Domain.Apps.Entities.Contents.Repositories; @@ -20,6 +21,7 @@ using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Xunit; +using TestUtils = Squidex.Domain.Apps.Core.TestHelpers.TestUtils; namespace Squidex.Domain.Apps.Entities.Contents.Queries { @@ -46,7 +48,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries schema = Mocks.Schema(appId, schemaId, schemaDef); schemaProvider = x => Task.FromResult(schema); - sut = new ConvertData(urlGenerator, assetRepository, contentRepository); + sut = new ConvertData(urlGenerator, TestUtils.DefaultSerializer, assetRepository, contentRepository); } [Fact] diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs index 3cc88a6eb..5c9857b28 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; +using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Contents.Text.State; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs index 1fc794f75..1f79dbe97 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/AExtensions.cs @@ -44,20 +44,5 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers { return that.Matches(x => x.ToString() == query); } - - public static T[] Is(this INegatableArgumentConstraintManager that, params T[]? values) - { - return values == null ? that.IsNull() : that.IsSameSequenceAs(values); - } - - public static HashSet Is(this INegatableArgumentConstraintManager> that, IEnumerable? values) - { - return values == null ? that.IsNull() : that.Matches(x => x.Intersect(values).Count() == values.Count()); - } - - public static HashSet Is(this INegatableArgumentConstraintManager> that, params T[]? values) - { - return values == null ? that.IsNull() : that.Matches(x => x.Intersect(values).Count() == values.Length); - } } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/JsonHelper.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/JsonHelper.cs deleted file mode 100644 index 470c92fa9..000000000 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/JsonHelper.cs +++ /dev/null @@ -1,69 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Squidex.Infrastructure.Json; -using Squidex.Infrastructure.Json.Newtonsoft; -using Squidex.Infrastructure.Queries.Json; -using Squidex.Infrastructure.Reflection; - -namespace Squidex.Domain.Apps.Entities.TestHelpers -{ - public static class JsonHelper - { - public static readonly IJsonSerializer DefaultSerializer = CreateSerializer(); - - public static IJsonSerializer CreateSerializer(TypeNameRegistry? typeNameRegistry = null) - { - var serializerSettings = DefaultSettings(typeNameRegistry); - - return new NewtonsoftJsonSerializer(serializerSettings); - } - - public static JsonSerializerSettings DefaultSettings(TypeNameRegistry? typeNameRegistry = null) - { - return new JsonSerializerSettings - { - SerializationBinder = new TypeNameSerializationBinder(typeNameRegistry ?? new TypeNameRegistry()), - - ContractResolver = new ConverterContractResolver( - new ClaimsPrincipalConverter(), - new InstantConverter(), - new EnvelopeHeadersConverter(), - new FilterConverter(), - new JsonValueConverter(), - new LanguageConverter(), - new NamedDomainIdConverter(), - new NamedGuidIdConverter(), - new NamedLongIdConverter(), - new NamedStringIdConverter(), - new PropertyPathConverter(), - new RefTokenConverter(), - new StringEnumConverter()), - - TypeNameHandling = TypeNameHandling.Auto - }; - } - - public static T SerializeAndDeserialize(this T value) - { - return DefaultSerializer.Deserialize>(DefaultSerializer.Serialize(Tuple.Create(value))).Item1; - } - - public static T Deserialize(string value) - { - return DefaultSerializer.Deserialize>($"{{ \"Item1\": \"{value}\" }}").Item1; - } - - public static T Deserialize(object value) - { - return DefaultSerializer.Deserialize>($"{{ \"Item1\": {value} }}").Item1; - } - } -}