From 9b3a52212f6d6deb411635a65a65e6eebb85d40e Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Fri, 19 Jul 2019 12:12:34 +0200 Subject: [PATCH] Temp --- .../ContentReferencesExtensions.cs | 42 +++++-- .../ReferencesExtensions.cs | 10 +- .../Contents/ContentEnricher.cs | 104 ++++++++++++++++-- .../Contents/ContentEntity.cs | 2 + .../Contents/ContextExtensions.cs | 20 ++++ src/Squidex.Domain.Apps.Entities/Context.cs | 16 ++- .../ReferenceExtractionTests.cs | 24 ++-- 7 files changed, 185 insertions(+), 33 deletions(-) diff --git a/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs b/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs index 125d529f2..6c7be128e 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs @@ -11,7 +11,6 @@ using System.Linq; 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.ExtractReferenceIds { @@ -25,18 +24,47 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds foreach (var field in schema.Fields) { - var fieldData = source.GetOrDefault(field.Id); + var ids = source.GetReferencedIds(field); - if (fieldData == null) + foreach (var id in ids) { - continue; + if (foundReferences.Add(id)) + { + yield return id; + } + } + } + } + + public static IEnumerable GetReferencedIds(this IdContentData source, IField field) + { + Guard.NotNull(field, nameof(field)); + + if (source.TryGetValue(field.Id, out var fieldData)) + { + foreach (var partitionValue in fieldData) + { + var ids = field.GetReferencedIds(partitionValue.Value); + + foreach (var id in ids) + { + yield return id; + } } + } + } - foreach (var partitionValue in fieldData.Where(x => x.Value.Type != JsonValueType.Null)) + public static IEnumerable GetReferencedIds(this NamedContentData source, IField field) + { + Guard.NotNull(field, nameof(field)); + + if (source.TryGetValue(field.Name, out var fieldData)) + { + foreach (var partitionValue in fieldData) { - var ids = field.ExtractReferences(partitionValue.Value); + var ids = field.GetReferencedIds(partitionValue.Value); - foreach (var id in ids.Where(x => foundReferences.Add(x))) + foreach (var id in ids) { yield return id; } diff --git a/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs b/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs index 0a701501f..0f65b224d 100644 --- a/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs +++ b/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure.Json.Objects; @@ -14,14 +15,14 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds { public static class ReferencesExtensions { - public static IEnumerable ExtractReferences(this IField field, IJsonValue value) + public static IEnumerable GetReferencedIds(this IField field, IJsonValue value) { return ReferencesExtractor.ExtractReferences(field, value); } public static IJsonValue CleanReferences(this IField field, IJsonValue value, ICollection oldReferences) { - if (value.Type == JsonValueType.Null) + if (IsNull(value)) { return value; } @@ -29,6 +30,11 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds return ReferencesCleaner.CleanReferences(field, value, oldReferences); } + private static bool IsNull(IJsonValue value) + { + return value == null || value.Type == JsonValueType.Null; + } + public static JsonArray ToJsonArray(this HashSet ids) { var result = JsonValue.Array(); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs index 32d93b04d..70734aa89 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs @@ -11,7 +11,10 @@ using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.ExtractReferenceIds; +using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure; +using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Reflection; @@ -20,14 +23,24 @@ namespace Squidex.Domain.Apps.Entities.Contents public sealed class ContentEnricher : IContentEnricher { private const string DefaultColor = StatusColors.Draft; + private readonly IAppProvider appProvider; + private readonly IContentQueryService contentQuery; private readonly IContentWorkflow contentWorkflow; private readonly IContextProvider contextProvider; - public ContentEnricher(IContentWorkflow contentWorkflow, IContextProvider contextProvider) + public ContentEnricher( + IAppProvider appProvider, + IContentQueryService contentQuery, + IContentWorkflow contentWorkflow, + IContextProvider contextProvider) { + Guard.NotNull(appProvider, nameof(appProvider)); + Guard.NotNull(contentQuery, nameof(contentQuery)); Guard.NotNull(contentWorkflow, nameof(contentWorkflow)); Guard.NotNull(contextProvider, nameof(contextProvider)); + this.appProvider = appProvider; + this.contentQuery = contentQuery; this.contentWorkflow = contentWorkflow; this.contextProvider = contextProvider; } @@ -50,27 +63,96 @@ namespace Squidex.Domain.Apps.Entities.Contents { var results = new List(); - var cache = new Dictionary<(Guid, Status), StatusInfo>(); - - foreach (var content in contents) + if (contents.Any()) { - var result = SimpleMapper.Map(content, new ContentEntity()); - - await ResolveColorAsync(content, result, cache); + var cache = new Dictionary<(Guid, Status), StatusInfo>(); - if (ShouldEnrichWithStatuses()) + foreach (var content in contents) { - await ResolveNextsAsync(content, result, user); - await ResolveCanUpdateAsync(content, result); + var result = SimpleMapper.Map(content, new ContentEntity()); + + await ResolveColorAsync(content, result, cache); + + if (ShouldEnrichWithStatuses()) + { + await ResolveNextsAsync(content, result, user); + await ResolveCanUpdateAsync(content, result); + } + + results.Add(result); } - results.Add(result); + if (contextProvider.Context.IsFrontendClient) + { + foreach (var group in results.GroupBy(x => x.SchemaId)) + { + await ResolveReferencesAsync(group.Key, group); + } + } } return results; } } + private async Task ResolveReferencesAsync(NamedId schemaId, IEnumerable contents) + { + var appId = contents.First().AppId.Id; + + var schema = await appProvider.GetSchemaAsync(appId, schemaId.Id); + + var referenceFields = + schema.SchemaDef.Fields.OfType>() + .Where(x => + x.Properties.MinItems == 1 && + x.Properties.MaxItems == 1 && + (x.Properties.IsListField || x.Properties.IsReferenceField)); + + foreach (var field in referenceFields) + { + var allIds = GetContentIds(contents, field); + + if (allIds.Count > 0) + { + var referenced = await contentQuery.QueryAsync(contextProvider.Context, schemaId.Id.ToString(), Q.Empty.WithIds(allIds)); + + var byId = referenced.ToDictionary(x => x.Id); + + foreach (var content in contents) + { + content.ReferenceData = content.ReferenceData ?? new NamedContentData(); + + if (content.DataDraft.TryGetValue(field.Name, out var fieldData)) + { + foreach (var partitionValue in fieldData.Where(x => x.Value.Type != JsonValueType.Null)) + { + var ids = field.GetReferencedIds(partitionValue.Value).ToArray(); + + if (ids.Length == 1) + { + if (byId.TryGetValue(ids[0], out var reference)) + { + } + } + } + } + } + } + } + } + + private static HashSet GetContentIds(IEnumerable contents, IField field) + { + var allIds = new HashSet(); + + foreach (var content in contents) + { + allIds.AddRange(content.DataDraft.GetReferencedIds(field)); + } + + return allIds; + } + private bool ShouldEnrichWithStatuses() { return contextProvider.Context.IsFrontendClient || contextProvider.Context.IsResolveFlow(); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs index 2e9f92115..31d6de3b8 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs @@ -36,6 +36,8 @@ namespace Squidex.Domain.Apps.Entities.Contents public NamedContentData DataDraft { get; set; } + public NamedContentData ReferenceData { get; set; } + public Status Status { get; set; } public StatusInfo[] Nexts { get; set; } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs index c88b4fae9..8dd9260c2 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContextExtensions.cs @@ -19,8 +19,28 @@ namespace Squidex.Domain.Apps.Entities.Contents private const string HeaderLanguages = "X-Languages"; private const string HeaderResolveFlow = "X-ResolveFlow"; private const string HeaderResolveAssetUrls = "X-Resolve-Urls"; + private const string HeaderNoEnrichment = "X-NoEnrichment"; private static readonly char[] Separators = { ',', ';' }; + public static bool IsNoEnrichment(this Context context) + { + return context.Headers.ContainsKey(HeaderNoEnrichment); + } + + public static Context WithNoEnrichment(this Context context, bool value = true) + { + if (value) + { + context.Headers[HeaderNoEnrichment] = "1"; + } + else + { + context.Headers.Remove(HeaderNoEnrichment); + } + + return context; + } + public static bool IsUnpublished(this Context context) { return context.Headers.ContainsKey(HeaderUnpublished); diff --git a/src/Squidex.Domain.Apps.Entities/Context.cs b/src/Squidex.Domain.Apps.Entities/Context.cs index d30e19c49..b0e393aa3 100644 --- a/src/Squidex.Domain.Apps.Entities/Context.cs +++ b/src/Squidex.Domain.Apps.Entities/Context.cs @@ -28,6 +28,11 @@ namespace Squidex.Domain.Apps.Entities get { return User?.Permissions() ?? PermissionSet.Empty; } } + public bool IsFrontendClient + { + get { return User != null && User.IsInClient(DefaultClients.Frontend); } + } + public Context() { } @@ -39,9 +44,16 @@ namespace Squidex.Domain.Apps.Entities App = app; } - public bool IsFrontendClient + public Context Clone() { - get { return User != null && User.IsInClient(DefaultClients.Frontend); } + var clone = new Context(User, App); + + foreach (var kvp in Headers) + { + clone.Headers[kvp.Key] = kvp.Value; + } + + return clone; } } } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs index 453c602c9..13ca9d77c 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs @@ -86,7 +86,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var sut = Fields.Assets(1, "my-asset", Partitioning.Invariant); - var result = sut.ExtractReferences(CreateValue(id1, id2)).ToArray(); + var result = sut.GetReferencedIds(CreateValue(id1, id2)).ToArray(); Assert.Equal(new[] { id1, id2 }, result); } @@ -96,7 +96,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds { var sut = Fields.Assets(1, "my-asset", Partitioning.Invariant); - var result = sut.ExtractReferences(null).ToArray(); + var result = sut.GetReferencedIds(null).ToArray(); Assert.Empty(result); } @@ -106,7 +106,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds { var sut = Fields.Assets(1, "my-asset", Partitioning.Invariant); - var result = sut.ExtractReferences(JsonValue.Create("invalid")).ToArray(); + var result = sut.GetReferencedIds(JsonValue.Create("invalid")).ToArray(); Assert.Empty(result); } @@ -116,7 +116,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds { var sut = Fields.String(1, "my-string", Partitioning.Invariant); - var result = sut.ExtractReferences(JsonValue.Create("invalid")).ToArray(); + var result = sut.GetReferencedIds(JsonValue.Create("invalid")).ToArray(); Assert.Empty(result); } @@ -153,6 +153,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var sut = Fields.Assets(1, "my-asset", Partitioning.Invariant); var token = CreateValue(id1, id2); + var result = sut.CleanReferences(token, HashSet.Of(Guid.NewGuid())); Assert.Same(token, result); @@ -174,7 +175,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds JsonValue.Object() .Add("my-refs", CreateValue(id1, id2))); - var result = sut.ExtractReferences(value).ToArray(); + var result = sut.GetReferencedIds(value).ToArray(); Assert.Equal(new[] { id1, id2, schemaId }, result); } @@ -188,7 +189,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var sut = Fields.References(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId }); - var result = sut.ExtractReferences(CreateValue(id1, id2)).ToArray(); + var result = sut.GetReferencedIds(CreateValue(id1, id2)).ToArray(); Assert.Equal(new[] { id1, id2, schemaId }, result); } @@ -199,7 +200,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var sut = Fields.References(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId }); - var result = sut.ExtractReferences(JsonValue.Null).ToArray(); + var result = sut.GetReferencedIds(JsonValue.Null).ToArray(); Assert.Equal(new[] { schemaId }, result); } @@ -210,7 +211,7 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var sut = Fields.References(1, "my-refs", Partitioning.Invariant, new ReferencesFieldProperties { SchemaId = schemaId }); - var result = sut.ExtractReferences(JsonValue.Create("invalid")).ToArray(); + var result = sut.GetReferencedIds(JsonValue.Create("invalid")).ToArray(); Assert.Equal(new[] { schemaId }, result); } @@ -261,10 +262,11 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds var sut = Fields.References(1, "my-refs", Partitioning.Invariant); - var token = CreateValue(id1, id2); - var result = sut.CleanReferences(token, HashSet.Of(Guid.NewGuid())); + var value = CreateValue(id1, id2); - Assert.Same(token, result); + var result = sut.CleanReferences(value, HashSet.Of(Guid.NewGuid())); + + Assert.Same(value, result); } private static IJsonValue CreateValue(params Guid[] ids)