mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
17 changed files with 1392 additions and 756 deletions
@ -0,0 +1,51 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ConvertContent |
||||
|
{ |
||||
|
public sealed class AddSchemaNames : IContentItemConverter |
||||
|
{ |
||||
|
private readonly ResolvedComponents components; |
||||
|
|
||||
|
public AddSchemaNames(ResolvedComponents components) |
||||
|
{ |
||||
|
this.components = components; |
||||
|
} |
||||
|
|
||||
|
public JsonObject ConvertItem(IField field, JsonObject source) |
||||
|
{ |
||||
|
if (field is IArrayField) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
if (source.ContainsKey("schemaName")) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
if (!Component.IsValid(source, out var discriminator)) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
var id = DomainId.Create(discriminator); |
||||
|
|
||||
|
if (components.TryGetValue(id, out var schema)) |
||||
|
{ |
||||
|
source["schemaName"] = schema.Name; |
||||
|
} |
||||
|
|
||||
|
return source; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Domain.Apps.Core.ValidateContent; |
||||
|
using Squidex.Infrastructure.Json; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ConvertContent |
||||
|
{ |
||||
|
public sealed class ExcludeChangedTypes : IContentFieldConverter, IContentValueConverter |
||||
|
{ |
||||
|
private readonly IJsonSerializer jsonSerializer; |
||||
|
|
||||
|
public ExcludeChangedTypes(IJsonSerializer jsonSerializer) |
||||
|
{ |
||||
|
this.jsonSerializer = jsonSerializer; |
||||
|
} |
||||
|
|
||||
|
public ContentFieldData? ConvertField(IRootField field, ContentFieldData source) |
||||
|
{ |
||||
|
foreach (var (_, value) in source) |
||||
|
{ |
||||
|
if (value.Value == default) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (IsChangedType(field, value)) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
public (bool Remove, JsonValue) ConvertValue(IField field, JsonValue source, IField? parent) |
||||
|
{ |
||||
|
if (parent == null || source == default) |
||||
|
{ |
||||
|
return (false, source); |
||||
|
} |
||||
|
|
||||
|
return (IsChangedType(field, source), source); |
||||
|
} |
||||
|
|
||||
|
private bool IsChangedType(IField field, JsonValue source) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
return !JsonValueValidator.IsValid(field, source, jsonSerializer); |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ConvertContent |
||||
|
{ |
||||
|
public sealed class ExcludeHidden : IContentFieldConverter, IContentValueConverter |
||||
|
{ |
||||
|
public static readonly ExcludeHidden Instance = new ExcludeHidden(); |
||||
|
|
||||
|
private ExcludeHidden() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public ContentFieldData? ConvertField(IRootField field, ContentFieldData source) |
||||
|
{ |
||||
|
return field.IsForApi() ? source : null; |
||||
|
} |
||||
|
|
||||
|
public (bool Remove, JsonValue) ConvertValue(IField field, JsonValue source, IField? parent) |
||||
|
{ |
||||
|
return field.IsForApi() ? (false, source) : (true, default); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,403 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Squidex.Domain.Apps.Core.Apps; |
|
||||
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; |
|
||||
|
|
||||
#pragma warning disable MA0048 // File name must match type name
|
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.ConvertContent |
|
||||
{ |
|
||||
public delegate ContentFieldData? FieldConverter(ContentFieldData data, IRootField field); |
|
||||
|
|
||||
public static class FieldConverters |
|
||||
{ |
|
||||
public static readonly FieldConverter Noop = (data, _) => data; |
|
||||
|
|
||||
public static readonly FieldConverter ExcludeHidden = (data, field) => |
|
||||
{ |
|
||||
return field.IsForApi() ? data : null; |
|
||||
}; |
|
||||
|
|
||||
public static FieldConverter ExcludeChangedTypes(IJsonSerializer jsonSerializer) |
|
||||
{ |
|
||||
return (data, field) => |
|
||||
{ |
|
||||
foreach (var (_, value) in data) |
|
||||
{ |
|
||||
if (value.Value == default) |
|
||||
{ |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
if (!JsonValueValidator.IsValid(field, value, jsonSerializer)) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return data; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public static FieldConverter ResolveInvariant(LanguagesConfig languages) |
|
||||
{ |
|
||||
var iv = InvariantPartitioning.Key; |
|
||||
|
|
||||
return (data, field) => |
|
||||
{ |
|
||||
if (field.Partitioning.Equals(Partitioning.Invariant) && !data.TryGetNonNull(iv, out _)) |
|
||||
{ |
|
||||
var result = new ContentFieldData(1); |
|
||||
|
|
||||
if (data.TryGetNonNull(languages.Master, out var value)) |
|
||||
{ |
|
||||
result[iv] = value; |
|
||||
} |
|
||||
else if (data.Count > 0) |
|
||||
{ |
|
||||
result[iv] = data.First().Value; |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
return data; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public static FieldConverter ResolveLanguages(LanguagesConfig languages) |
|
||||
{ |
|
||||
var iv = InvariantPartitioning.Key; |
|
||||
|
|
||||
return (data, field) => |
|
||||
{ |
|
||||
if (field.Partitioning.Equals(Partitioning.Language)) |
|
||||
{ |
|
||||
if (data.TryGetNonNull(iv, out var value)) |
|
||||
{ |
|
||||
var result = new ContentFieldData |
|
||||
{ |
|
||||
[languages.Master] = value |
|
||||
}; |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
while (true) |
|
||||
{ |
|
||||
var isRemoved = false; |
|
||||
|
|
||||
foreach (var (key, _) in data) |
|
||||
{ |
|
||||
if (!languages.AllKeys.Contains(key)) |
|
||||
{ |
|
||||
data.Remove(key); |
|
||||
isRemoved = true; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (!isRemoved) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return data; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public static FieldConverter ResolveFallbackLanguages(LanguagesConfig languages) |
|
||||
{ |
|
||||
return (data, field) => |
|
||||
{ |
|
||||
if (field.Partitioning.Equals(Partitioning.Language)) |
|
||||
{ |
|
||||
foreach (var languageCode in languages.AllKeys) |
|
||||
{ |
|
||||
if (data.TryGetNonNull(languageCode, out _)) |
|
||||
{ |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
foreach (var fallback in languages.GetPriorities(languageCode)) |
|
||||
{ |
|
||||
if (data.TryGetNonNull(fallback, out var value)) |
|
||||
{ |
|
||||
data[languageCode] = value; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return data; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public static FieldConverter FilterLanguages(LanguagesConfig config, IEnumerable<Language>? languages) |
|
||||
{ |
|
||||
if (languages?.Any() != true) |
|
||||
{ |
|
||||
return Noop; |
|
||||
} |
|
||||
|
|
||||
var languageSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); |
|
||||
|
|
||||
foreach (var language in languages) |
|
||||
{ |
|
||||
if (config.Contains(language.Iso2Code)) |
|
||||
{ |
|
||||
languageSet.Add(language.Iso2Code); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (languageSet.Count == 0) |
|
||||
{ |
|
||||
languageSet.Add(config.Master); |
|
||||
} |
|
||||
|
|
||||
return (data, field) => |
|
||||
{ |
|
||||
if (field.Partitioning.Equals(Partitioning.Language)) |
|
||||
{ |
|
||||
while (true) |
|
||||
{ |
|
||||
var isRemoved = false; |
|
||||
|
|
||||
foreach (var (key, _) in data) |
|
||||
{ |
|
||||
if (!languageSet.Contains(key)) |
|
||||
{ |
|
||||
data.Remove(key); |
|
||||
isRemoved = true; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (!isRemoved) |
|
||||
{ |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return data; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public static FieldConverter ForValues(ResolvedComponents components, params ValueConverter[] converters) |
|
||||
{ |
|
||||
return (data, field) => |
|
||||
{ |
|
||||
ContentFieldData? newData = null; |
|
||||
|
|
||||
foreach (var (key, value) in data) |
|
||||
{ |
|
||||
var newValue = ConvertByType(field, value, null, converters, components); |
|
||||
|
|
||||
if (newValue == null) |
|
||||
{ |
|
||||
newData ??= new ContentFieldData(data); |
|
||||
newData.Remove(key); |
|
||||
} |
|
||||
else if (!ReferenceEquals(newValue.Value.Value, value.Value)) |
|
||||
{ |
|
||||
newData ??= new ContentFieldData(data); |
|
||||
newData[key] = newValue.Value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return newData ?? data; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
private static JsonValue? ConvertByType<T>(T field, JsonValue value, IArrayField? parent, ValueConverter[] converters, |
|
||||
ResolvedComponents components) where T : IField |
|
||||
{ |
|
||||
switch (field) |
|
||||
{ |
|
||||
case IArrayField arrayField: |
|
||||
return ConvertArray(arrayField, value, converters, components); |
|
||||
|
|
||||
case IField<ComponentFieldProperties>: |
|
||||
return ConvertComponent(value, converters, components); |
|
||||
|
|
||||
case IField<ComponentsFieldProperties>: |
|
||||
return ConvertComponents(value, converters, components); |
|
||||
|
|
||||
default: |
|
||||
return ConvertValue(field, value, parent, converters); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static JsonValue? ConvertArray(IArrayField field, JsonValue value, ValueConverter[] converters, |
|
||||
ResolvedComponents components) |
|
||||
{ |
|
||||
if (value.Value is JsonArray a) |
|
||||
{ |
|
||||
JsonArray? result = null; |
|
||||
|
|
||||
for (int i = 0, j = 0; i < a.Count; i++, j++) |
|
||||
{ |
|
||||
var oldValue = a[i]; |
|
||||
|
|
||||
var newValue = ConvertArrayItem(field, oldValue, converters, components); |
|
||||
|
|
||||
if (newValue == null) |
|
||||
{ |
|
||||
result ??= new JsonArray(a); |
|
||||
result.RemoveAt(j); |
|
||||
j--; |
|
||||
} |
|
||||
else if (!ReferenceEquals(newValue.Value.Value, oldValue.Value)) |
|
||||
{ |
|
||||
result ??= new JsonArray(a); |
|
||||
result[j] = newValue.Value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return result ?? value; |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
private static JsonValue? ConvertComponents(JsonValue? value, ValueConverter[] converters, |
|
||||
ResolvedComponents components) |
|
||||
{ |
|
||||
if (value?.Value is JsonArray a) |
|
||||
{ |
|
||||
JsonArray? result = null; |
|
||||
|
|
||||
for (int i = 0, j = 0; i < a.Count; i++, j++) |
|
||||
{ |
|
||||
var oldValue = a[i]; |
|
||||
|
|
||||
var newValue = ConvertComponent(oldValue, converters, components); |
|
||||
|
|
||||
if (newValue == null) |
|
||||
{ |
|
||||
result ??= new JsonArray(a); |
|
||||
result.RemoveAt(j); |
|
||||
j--; |
|
||||
} |
|
||||
else if (!ReferenceEquals(newValue.Value.Value, a[i].Value)) |
|
||||
{ |
|
||||
result ??= new JsonArray(a); |
|
||||
result[j] = newValue.Value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return result ?? value; |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
private static JsonValue? ConvertComponent(JsonValue? value, ValueConverter[] converters, |
|
||||
ResolvedComponents components) |
|
||||
{ |
|
||||
if (value?.Value is JsonObject o && o.TryGetValue(Component.Discriminator, out var found) && found.Value is string s) |
|
||||
{ |
|
||||
var id = DomainId.Create(s); |
|
||||
|
|
||||
if (components.TryGetValue(id, out var schema)) |
|
||||
{ |
|
||||
return ConvertNested(schema.FieldCollection, value.Value, null, converters, components); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
private static JsonValue? ConvertArrayItem(IArrayField field, JsonValue value, ValueConverter[] converters, |
|
||||
ResolvedComponents components) |
|
||||
{ |
|
||||
if (value.Value is JsonObject) |
|
||||
{ |
|
||||
return ConvertNested(field.FieldCollection, value, field, converters, components); |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
private static JsonValue ConvertNested<T>(FieldCollection<T> fields, JsonValue source, IArrayField? parent, ValueConverter[] converters, |
|
||||
ResolvedComponents components) where T : IField |
|
||||
{ |
|
||||
JsonObject? result = null; |
|
||||
|
|
||||
var obj = source.AsObject; |
|
||||
|
|
||||
foreach (var (key, value) in obj) |
|
||||
{ |
|
||||
JsonValue? newValue = value; |
|
||||
|
|
||||
if (fields.ByName.TryGetValue(key, out var field)) |
|
||||
{ |
|
||||
newValue = ConvertByType(field, value, parent, converters, components); |
|
||||
} |
|
||||
else if (key != Component.Discriminator) |
|
||||
{ |
|
||||
newValue = null; |
|
||||
} |
|
||||
|
|
||||
if (newValue == null) |
|
||||
{ |
|
||||
result ??= new JsonObject(obj); |
|
||||
result.Remove(key); |
|
||||
} |
|
||||
else if (!ReferenceEquals(newValue.Value.Value, value.Value)) |
|
||||
{ |
|
||||
result ??= new JsonObject(obj); |
|
||||
result[key] = newValue.Value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return result ?? source; |
|
||||
} |
|
||||
|
|
||||
private static JsonValue? ConvertValue(IField field, JsonValue value, IArrayField? parent, ValueConverter[] converters) |
|
||||
{ |
|
||||
var newValue = value; |
|
||||
|
|
||||
for (var i = 0; i < converters.Length; i++) |
|
||||
{ |
|
||||
var candidate = converters[i](newValue!, field, parent); |
|
||||
|
|
||||
if (candidate == null) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
newValue = candidate.Value; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return newValue; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,39 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
|
||||
|
#pragma warning disable MA0048 // File name must match type name
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ConvertContent |
||||
|
{ |
||||
|
public interface IConverter |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public interface IContentFieldAfterConverter : IConverter |
||||
|
{ |
||||
|
ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source); |
||||
|
} |
||||
|
|
||||
|
public interface IContentFieldConverter : IConverter |
||||
|
{ |
||||
|
ContentFieldData? ConvertField(IRootField field, ContentFieldData source); |
||||
|
} |
||||
|
|
||||
|
public interface IContentItemConverter : IConverter |
||||
|
{ |
||||
|
JsonObject ConvertItem(IField field, JsonObject source); |
||||
|
} |
||||
|
|
||||
|
public interface IContentValueConverter : IConverter |
||||
|
{ |
||||
|
(bool Remove, JsonValue) ConvertValue(IField field, JsonValue source, IField? parent); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Json.Objects; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ConvertContent |
||||
|
{ |
||||
|
public sealed class ResolveAssetUrls : IContentValueConverter |
||||
|
{ |
||||
|
private readonly NamedId<DomainId> appId; |
||||
|
private readonly IUrlGenerator urlGenerator; |
||||
|
private readonly Func<IField, IField?, bool> shouldHandle; |
||||
|
|
||||
|
public ResolveAssetUrls(NamedId<DomainId> appId, IUrlGenerator urlGenerator, IReadOnlyCollection<string>? fields) |
||||
|
{ |
||||
|
this.appId = appId; |
||||
|
|
||||
|
if (fields == null || fields.Count == 0) |
||||
|
{ |
||||
|
shouldHandle = (field, parent) => false; |
||||
|
} |
||||
|
else if (fields.Contains("*")) |
||||
|
{ |
||||
|
shouldHandle = (field, parent) => true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var paths = fields.Select(x => x.Split('.')).ToList(); |
||||
|
|
||||
|
shouldHandle = (field, parent) => |
||||
|
{ |
||||
|
for (var i = 0; i < paths.Count; i++) |
||||
|
{ |
||||
|
var path = paths[i]; |
||||
|
|
||||
|
if (parent != null) |
||||
|
{ |
||||
|
if (path.Length == 2 && path[0] == parent.Name && path[1] == field.Name) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (path.Length == 1 && path[0] == field.Name) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
this.urlGenerator = urlGenerator; |
||||
|
} |
||||
|
|
||||
|
public (bool Remove, JsonValue) ConvertValue(IField field, JsonValue source, IField? parent) |
||||
|
{ |
||||
|
if (field is IField<AssetsFieldProperties> && source.Value is JsonArray a && shouldHandle(field, parent)) |
||||
|
{ |
||||
|
for (var i = 0; i < a.Count; i++) |
||||
|
{ |
||||
|
a[i] = urlGenerator.AssetContent(appId, a[i].ToString()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return (false, source); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ConvertContent |
||||
|
{ |
||||
|
public sealed class ResolveInvariant : IContentFieldAfterConverter |
||||
|
{ |
||||
|
private readonly LanguagesConfig languages; |
||||
|
|
||||
|
public ResolveInvariant(LanguagesConfig languages) |
||||
|
{ |
||||
|
this.languages = languages; |
||||
|
} |
||||
|
|
||||
|
public ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source) |
||||
|
{ |
||||
|
if (!field.Partitioning.Equals(Partitioning.Invariant)) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
if (source.TryGetNonNull(InvariantPartitioning.Key, out _)) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
if (source.TryGetNonNull(languages.Master, out var value)) |
||||
|
{ |
||||
|
source.Clear(); |
||||
|
source[InvariantPartitioning.Key] = value; |
||||
|
|
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
if (source.Count > 0) |
||||
|
{ |
||||
|
var first = source.First().Value; |
||||
|
|
||||
|
source.Clear(); |
||||
|
source[InvariantPartitioning.Key] = first; |
||||
|
|
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
source.Clear(); |
||||
|
|
||||
|
return source; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,104 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.ConvertContent |
||||
|
{ |
||||
|
public sealed class ResolveLanguages : IContentFieldAfterConverter |
||||
|
{ |
||||
|
private readonly LanguagesConfig languages; |
||||
|
private readonly bool resolveFallback; |
||||
|
private readonly HashSet<string> languageCodes; |
||||
|
|
||||
|
public ResolveLanguages(LanguagesConfig languages, bool resolveFallback = true, params Language[] filteredLanguages) |
||||
|
{ |
||||
|
this.languages = languages; |
||||
|
|
||||
|
if (filteredLanguages?.Length > 0) |
||||
|
{ |
||||
|
languageCodes = languages.AllKeys.Intersect(filteredLanguages.Select(x => x.Iso2Code)).ToHashSet(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
languageCodes = languages.AllKeys.ToHashSet(); |
||||
|
} |
||||
|
|
||||
|
if (languageCodes.Count == 0) |
||||
|
{ |
||||
|
languageCodes.Add(languages.Master); |
||||
|
} |
||||
|
|
||||
|
this.resolveFallback = resolveFallback; |
||||
|
} |
||||
|
|
||||
|
public ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source) |
||||
|
{ |
||||
|
if (!field.Partitioning.Equals(Partitioning.Language)) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
if (source.TryGetNonNull(InvariantPartitioning.Key, out var value)) |
||||
|
{ |
||||
|
var result = new ContentFieldData |
||||
|
{ |
||||
|
[languages.Master] = value |
||||
|
}; |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
while (true) |
||||
|
{ |
||||
|
var isRemoved = false; |
||||
|
|
||||
|
foreach (var (key, _) in source) |
||||
|
{ |
||||
|
if (!languageCodes.Contains(key)) |
||||
|
{ |
||||
|
source.Remove(key); |
||||
|
isRemoved = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!isRemoved) |
||||
|
{ |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!resolveFallback) |
||||
|
{ |
||||
|
return source; |
||||
|
} |
||||
|
|
||||
|
foreach (var languageCode in languageCodes) |
||||
|
{ |
||||
|
if (source.TryGetNonNull(languageCode, out _)) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
foreach (var fallback in languages.GetPriorities(languageCode)) |
||||
|
{ |
||||
|
if (source.TryGetNonNull(fallback, out var fallbackValue)) |
||||
|
{ |
||||
|
source[languageCode] = fallbackValue; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return source; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,111 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Squidex.Domain.Apps.Core.Schemas; |
|
||||
using Squidex.Domain.Apps.Core.ValidateContent; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.Json; |
|
||||
using Squidex.Infrastructure.Json.Objects; |
|
||||
|
|
||||
#pragma warning disable MA0048 // File name must match type name
|
|
||||
|
|
||||
namespace Squidex.Domain.Apps.Core.ConvertContent |
|
||||
{ |
|
||||
public delegate JsonValue? ValueConverter(JsonValue value, IField field, IArrayField? parent); |
|
||||
|
|
||||
public static class ValueConverters |
|
||||
{ |
|
||||
public static readonly ValueConverter Noop = (value, field, parent) => value; |
|
||||
|
|
||||
public static readonly ValueConverter ExcludeHidden = (value, field, parent) => |
|
||||
{ |
|
||||
return field.IsForApi() ? (JsonValue?)value : null; |
|
||||
}; |
|
||||
|
|
||||
public static ValueConverter ExcludeChangedTypes(IJsonSerializer jsonSerializer) |
|
||||
{ |
|
||||
return (value, field, parent) => |
|
||||
{ |
|
||||
if (value == default) |
|
||||
{ |
|
||||
return value; |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
if (!JsonValueValidator.IsValid(field, value, jsonSerializer)) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public static ValueConverter ResolveAssetUrls(NamedId<DomainId> appId, IReadOnlyCollection<string>? fields, IUrlGenerator urlGenerator) |
|
||||
{ |
|
||||
if (fields?.Any() != true) |
|
||||
{ |
|
||||
return Noop; |
|
||||
} |
|
||||
|
|
||||
Func<IField, IField?, bool> shouldHandle; |
|
||||
|
|
||||
if (fields.Contains("*")) |
|
||||
{ |
|
||||
shouldHandle = (field, parent) => true; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
var paths = fields.Select(x => x.Split('.')).ToList(); |
|
||||
|
|
||||
shouldHandle = (field, parent) => |
|
||||
{ |
|
||||
for (var i = 0; i < paths.Count; i++) |
|
||||
{ |
|
||||
var path = paths[i]; |
|
||||
|
|
||||
if (parent != null) |
|
||||
{ |
|
||||
if (path.Length == 2 && path[0] == parent.Name && path[1] == field.Name) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
if (path.Length == 1 && path[0] == field.Name) |
|
||||
{ |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
return (value, field, parent) => |
|
||||
{ |
|
||||
if (field is IField<AssetsFieldProperties> && value.Value is JsonArray a && shouldHandle(field, parent)) |
|
||||
{ |
|
||||
for (var i = 0; i < a.Count; i++) |
|
||||
{ |
|
||||
a[i] = urlGenerator.AssetContent(appId, a[i].ToString()); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return value; |
|
||||
}; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue