mirror of https://github.com/Squidex/squidex.git
Browse Source
* Simplified data usage. * Code simplified. * Fixed tests. * Migration fixed.pull/627/head
committed by
GitHub
127 changed files with 815 additions and 1359 deletions
@ -0,0 +1,17 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Contents |
||||
|
{ |
||||
|
public enum GeoJsonParseResult |
||||
|
{ |
||||
|
Success, |
||||
|
InvalidLatitude, |
||||
|
InvalidLongitude, |
||||
|
InvalidValue |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using GeoJSON.Net; |
||||
|
using GeoJSON.Net.Geometry; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Json; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
using Squidex.Infrastructure.ObjectPool; |
||||
|
using Squidex.Infrastructure.Validation; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Contents |
||||
|
{ |
||||
|
public static class GeoJsonValue |
||||
|
{ |
||||
|
public static GeoJsonParseResult TryParse(IJsonValue value, IJsonSerializer serializer, out GeoJSONObject geoJSON) |
||||
|
{ |
||||
|
Guard.NotNull(serializer, nameof(serializer)); |
||||
|
Guard.NotNull(value, nameof(value)); |
||||
|
|
||||
|
geoJSON = null!; |
||||
|
|
||||
|
if (value is JsonObject geoObject) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var stream = DefaultPools.MemoryStream.Get(); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
serializer.Serialize(value, stream, true); |
||||
|
|
||||
|
stream.Position = 0; |
||||
|
|
||||
|
geoJSON = serializer.Deserialize<GeoJSONObject>(stream, null, leaveOpen: true); |
||||
|
|
||||
|
return GeoJsonParseResult.Success; |
||||
|
} |
||||
|
finally |
||||
|
{ |
||||
|
DefaultPools.MemoryStream.Return(stream); |
||||
|
} |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
if (geoObject.TryGetValue<JsonNumber>("latitude", out var lat)) |
||||
|
{ |
||||
|
if (!lat.Value.IsBetween(-90, 90)) |
||||
|
{ |
||||
|
return GeoJsonParseResult.InvalidLatitude; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (geoObject.TryGetValue<JsonNumber>("longitude", out var lon)) |
||||
|
{ |
||||
|
if (!lon.Value.IsBetween(-180, 180)) |
||||
|
{ |
||||
|
return GeoJsonParseResult.InvalidLongitude; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
geoJSON = new Point(new Position(lat!.Value, lon!.Value)); |
||||
|
|
||||
|
return GeoJsonParseResult.Success; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return GeoJsonParseResult.InvalidValue; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,57 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
#pragma warning disable CA1067 // Override Object.Equals(object) when implementing IEquatable<T>
|
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.Contents |
|
||||
{ |
|
||||
public sealed class IdContentData : ContentData<long>, IEquatable<IdContentData> |
|
||||
{ |
|
||||
public IdContentData() |
|
||||
: base(EqualityComparer<long>.Default) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public IdContentData(int capacity) |
|
||||
: base(capacity, EqualityComparer<long>.Default) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public static IdContentData Merge(params IdContentData[] contents) |
|
||||
{ |
|
||||
return MergeTo(new IdContentData(), contents); |
|
||||
} |
|
||||
|
|
||||
public IdContentData MergeInto(IdContentData target) |
|
||||
{ |
|
||||
return Merge(target, this); |
|
||||
} |
|
||||
|
|
||||
public IdContentData ToCleaned() |
|
||||
{ |
|
||||
return Clean(this, new IdContentData()); |
|
||||
} |
|
||||
|
|
||||
public IdContentData AddField(long id, ContentFieldData? data) |
|
||||
{ |
|
||||
Guard.GreaterThan(id, 0, nameof(id)); |
|
||||
|
|
||||
this[id] = data; |
|
||||
|
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public bool Equals(IdContentData? other) |
|
||||
{ |
|
||||
return base.Equals(other); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,79 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Linq; |
|
||||
using Squidex.Infrastructure; |
|
||||
|
|
||||
#pragma warning disable CA1067 // Override Object.Equals(object) when implementing IEquatable<T>
|
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.Contents |
|
||||
{ |
|
||||
public sealed class NamedContentData : ContentData<string>, IEquatable<NamedContentData> |
|
||||
{ |
|
||||
public NamedContentData() |
|
||||
: base(StringComparer.Ordinal) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public NamedContentData(NamedContentData source) |
|
||||
: base(source, StringComparer.Ordinal) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public NamedContentData(int capacity) |
|
||||
: base(capacity, StringComparer.Ordinal) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public static NamedContentData Merge(params NamedContentData[] contents) |
|
||||
{ |
|
||||
return MergeTo(new NamedContentData(), contents); |
|
||||
} |
|
||||
|
|
||||
public NamedContentData MergeInto(NamedContentData target) |
|
||||
{ |
|
||||
return Merge(target, this); |
|
||||
} |
|
||||
|
|
||||
public NamedContentData ToCleaned() |
|
||||
{ |
|
||||
return Clean(this, new NamedContentData()); |
|
||||
} |
|
||||
|
|
||||
public NamedContentData AddField(string name, ContentFieldData? data) |
|
||||
{ |
|
||||
Guard.NotNullOrEmpty(name, nameof(name)); |
|
||||
|
|
||||
this[name] = data; |
|
||||
|
|
||||
return this; |
|
||||
} |
|
||||
|
|
||||
public NamedContentData Clone() |
|
||||
{ |
|
||||
var clone = new NamedContentData(Count); |
|
||||
|
|
||||
foreach (var (key, value) in this) |
|
||||
{ |
|
||||
clone[key] = value?.Clone()!; |
|
||||
} |
|
||||
|
|
||||
return clone; |
|
||||
} |
|
||||
|
|
||||
public bool Equals(NamedContentData? other) |
|
||||
{ |
|
||||
return base.Equals(other); |
|
||||
} |
|
||||
|
|
||||
public override string ToString() |
|
||||
{ |
|
||||
return $"{{{string.Join(", ", this.Select(x => $"\"{x.Key}\":{x.Value}"))}}}";
|
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,53 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Collections.Generic; |
|
||||
using Squidex.Domain.Apps.Core.Schemas; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.ConvertContent |
|
||||
{ |
|
||||
public abstract class FieldIdentifier |
|
||||
{ |
|
||||
public static readonly FieldIdentifier ByName = new FieldByName(); |
|
||||
public static readonly FieldIdentifier ById = new FieldById(); |
|
||||
|
|
||||
public abstract IField? GetField(IArrayField arrayField, string key); |
|
||||
|
|
||||
public abstract string GetStringKey(IField field); |
|
||||
|
|
||||
private sealed class FieldByName : FieldIdentifier |
|
||||
{ |
|
||||
public override IField? GetField(IArrayField arrayField, string key) |
|
||||
{ |
|
||||
return arrayField.FieldsByName.GetValueOrDefault(key); |
|
||||
} |
|
||||
|
|
||||
public override string GetStringKey(IField field) |
|
||||
{ |
|
||||
return field.Name; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private sealed class FieldById : FieldIdentifier |
|
||||
{ |
|
||||
public override IField? GetField(IArrayField arrayField, string key) |
|
||||
{ |
|
||||
if (long.TryParse(key, out var id)) |
|
||||
{ |
|
||||
return arrayField.FieldsById.GetValueOrDefault(id); |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
public override string GetStringKey(IField field) |
|
||||
{ |
|
||||
return field.Id.ToString(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,148 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using NodaTime.Text; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Json; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ValidateContent |
||||
|
{ |
||||
|
public sealed class JsonValueValidator : IFieldVisitor<bool, JsonValueValidator.Args> |
||||
|
{ |
||||
|
private static readonly JsonValueValidator Instance = new JsonValueValidator(); |
||||
|
|
||||
|
public readonly struct Args |
||||
|
{ |
||||
|
public readonly IJsonValue Value; |
||||
|
public readonly IJsonSerializer JsonSerializer; |
||||
|
|
||||
|
public Args(IJsonValue value, IJsonSerializer jsonSerializer) |
||||
|
{ |
||||
|
Value = value; |
||||
|
|
||||
|
JsonSerializer = jsonSerializer; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private JsonValueValidator() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public static bool IsValid(IField field, IJsonValue value, IJsonSerializer jsonSerializer) |
||||
|
{ |
||||
|
Guard.NotNull(field, nameof(field)); |
||||
|
Guard.NotNull(value, nameof(value)); |
||||
|
|
||||
|
var args = new Args(value, jsonSerializer); |
||||
|
|
||||
|
return field.Accept(Instance, args); |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IArrayField field, Args args) |
||||
|
{ |
||||
|
return IsValidObjectList(args.Value); |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<AssetsFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return IsValidStringList(args.Value); |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<ReferencesFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return IsValidStringList(args.Value); |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<TagsFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return IsValidStringList(args.Value); |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<BooleanFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return args.Value is JsonBoolean; |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<NumberFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return args.Value is JsonNumber; |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<StringFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return args.Value is JsonString; |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<UIFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<DateTimeFieldProperties> field, Args args) |
||||
|
{ |
||||
|
if (args.Value.Type == JsonValueType.String) |
||||
|
{ |
||||
|
var parseResult = InstantPattern.General.Parse(args.Value.ToString()); |
||||
|
|
||||
|
return parseResult.Success; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<GeolocationFieldProperties> field, Args args) |
||||
|
{ |
||||
|
var result = GeoJsonValue.TryParse(args.Value, args.JsonSerializer, out _); |
||||
|
|
||||
|
return result == GeoJsonParseResult.Success; |
||||
|
} |
||||
|
|
||||
|
public bool Visit(IField<JsonFieldProperties> field, Args args) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
private static bool IsValidStringList(IJsonValue value) |
||||
|
{ |
||||
|
if (value is JsonArray array) |
||||
|
{ |
||||
|
foreach (var item in array) |
||||
|
{ |
||||
|
if (item is not JsonString) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
private static bool IsValidObjectList(IJsonValue value) |
||||
|
{ |
||||
|
if (value is JsonArray array) |
||||
|
{ |
||||
|
foreach (var item in array) |
||||
|
{ |
||||
|
if (item is not JsonObject) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,32 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using MongoDB.Bson.Serialization; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Assets |
|
||||
{ |
|
||||
internal static class Fields |
|
||||
{ |
|
||||
private static readonly Lazy<string> AssetIdField = new Lazy<string>(GetAssetIdField); |
|
||||
private static readonly Lazy<string> AssetFolderIdField = new Lazy<string>(GetAssetFolderIdField); |
|
||||
|
|
||||
public static string AssetId => AssetIdField.Value; |
|
||||
|
|
||||
public static string AssetFolderId => AssetFolderIdField.Value; |
|
||||
|
|
||||
private static string GetAssetIdField() |
|
||||
{ |
|
||||
return BsonClassMap.LookupClassMap(typeof(MongoAssetEntity)).GetMemberMap(nameof(MongoAssetEntity.Id)).ElementName; |
|
||||
} |
|
||||
|
|
||||
private static string GetAssetFolderIdField() |
|
||||
{ |
|
||||
return BsonClassMap.LookupClassMap(typeof(MongoAssetFolderEntity)).GetMemberMap(nameof(MongoAssetFolderEntity.Id)).ElementName; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,47 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Squidex.Domain.Apps.Core.Contents; |
|
||||
using Squidex.Domain.Apps.Core.ConvertContent; |
|
||||
using Squidex.Domain.Apps.Core.Schemas; |
|
||||
using Squidex.Infrastructure.Json; |
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Entities.MongoDb.Contents.Operations |
|
||||
{ |
|
||||
public sealed class DataConverter |
|
||||
{ |
|
||||
private readonly FieldConverter[] decodeJsonConverters; |
|
||||
private readonly FieldConverter[] encodeJsonConverters; |
|
||||
|
|
||||
public DataConverter(IJsonSerializer serializer) |
|
||||
{ |
|
||||
var decoder = ValueConverters.DecodeJson(serializer); |
|
||||
|
|
||||
decodeJsonConverters = new[] |
|
||||
{ |
|
||||
FieldConverters.ForValues(decoder, ValueConverters.ForNested(decoder)) |
|
||||
}; |
|
||||
|
|
||||
var encoder = ValueConverters.EncodeJson(serializer); |
|
||||
|
|
||||
encodeJsonConverters = new[] |
|
||||
{ |
|
||||
FieldConverters.ForValues(encoder, ValueConverters.ForNested(encoder)) |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public NamedContentData FromMongoModel(IdContentData result, Schema schema) |
|
||||
{ |
|
||||
return result.ConvertId2Name(schema, decodeJsonConverters); |
|
||||
} |
|
||||
|
|
||||
public IdContentData ToMongoModel(NamedContentData result, Schema schema) |
|
||||
{ |
|
||||
return result.ConvertName2IdCloned(schema, encodeJsonConverters); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,22 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.IO; |
||||
|
using System.Text; |
||||
|
using Microsoft.Extensions.ObjectPool; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.ObjectPool |
||||
|
{ |
||||
|
public static class DefaultPools |
||||
|
{ |
||||
|
public static readonly ObjectPool<MemoryStream> MemoryStream = |
||||
|
new DefaultObjectPool<MemoryStream>(new MemoryStreamPooledObjectPolicy()); |
||||
|
|
||||
|
public static readonly ObjectPool<StringBuilder> StringBuilder = |
||||
|
new DefaultObjectPool<StringBuilder>(new StringBuilderPooledObjectPolicy()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.IO; |
||||
|
using Microsoft.Extensions.ObjectPool; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.ObjectPool |
||||
|
{ |
||||
|
public sealed class MemoryStreamPooledObjectPolicy : PooledObjectPolicy<MemoryStream> |
||||
|
{ |
||||
|
public int InitialCapacity { get; set; } = 100; |
||||
|
|
||||
|
public int MaximumRetainedCapacity { get; set; } = 4 * 1024; |
||||
|
|
||||
|
public override MemoryStream Create() |
||||
|
{ |
||||
|
return new MemoryStream(InitialCapacity); |
||||
|
} |
||||
|
|
||||
|
public override bool Return(MemoryStream obj) |
||||
|
{ |
||||
|
if (obj.Capacity > MaximumRetainedCapacity) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
obj.Position = 0; |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue