Browse Source

Progress.

pull/388/head
Sebastian Stehle 7 years ago
parent
commit
9512b1da6f
  1. 2
      src/Squidex.Domain.Apps.Core.Model/Contents/ContentFieldData.cs
  2. 1
      src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs
  3. 5
      src/Squidex.Domain.Apps.Core.Model/InvariantPartitioning.cs
  4. 4
      src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs
  5. 70
      src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs
  6. 15
      src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/Ids.cs
  7. 5
      src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs
  8. 13
      src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs
  9. 2
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ObjectPath.cs
  10. 2
      src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs
  11. 4
      src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs
  12. 9
      src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs
  13. 115
      src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs
  14. 2
      src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs
  15. 5
      src/Squidex.Domain.Apps.Entities/Contents/IContentEnricher.cs
  16. 2
      src/Squidex.Domain.Apps.Entities/Contents/IEnrichedContentEntity.cs
  17. 2
      src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexerGrain.cs
  18. 1
      src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs
  19. 1
      src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs
  20. 5
      src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs
  21. 1
      src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs
  22. 1
      src/Squidex/Areas/Api/Controllers/History/HistoryController.cs
  23. 1
      src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemasDto.cs
  24. 3
      src/Squidex/Config/Domain/EntitiesServices.cs
  25. 30
      src/Squidex/app/features/content/shared/content-item.component.ts
  26. 34
      src/Squidex/app/features/content/shared/references-dropdown.component.ts
  27. 2
      src/Squidex/app/shared/services/contents.service.spec.ts
  28. 11
      src/Squidex/app/shared/services/contents.service.ts
  29. 102
      src/Squidex/app/shared/state/contents.forms.ts
  30. 2
      src/Squidex/appsettings.json
  31. 14
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs
  32. 81
      tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceFormattingTests.cs
  33. 13
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs
  34. 25
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEnricherTests.cs
  35. 2
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs

2
src/Squidex.Domain.Apps.Core.Model/Contents/ContentFieldData.cs

@ -21,7 +21,7 @@ namespace Squidex.Domain.Apps.Core.Contents
public ContentFieldData AddValue(object value)
{
return AddJsonValue(InvariantPartitioning.Instance.Master.Key, JsonValue.Create(value));
return AddJsonValue(InvariantPartitioning.Key, JsonValue.Create(value));
}
public ContentFieldData AddValue(string key, object value)

1
src/Squidex.Domain.Apps.Core.Model/Contents/Workflows.cs

@ -9,7 +9,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Threading.Tasks;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Collections;

5
src/Squidex.Domain.Apps.Core.Model/InvariantPartitioning.cs

@ -15,6 +15,7 @@ namespace Squidex.Domain.Apps.Core
public sealed class InvariantPartitioning : IFieldPartitioning, IFieldPartitionItem
{
public static readonly InvariantPartitioning Instance = new InvariantPartitioning();
public static readonly string Key = "iv";
public int Count
{
@ -28,7 +29,7 @@ namespace Squidex.Domain.Apps.Core
string IFieldPartitionItem.Key
{
get { return "iv"; }
get { return Key; }
}
string IFieldPartitionItem.Name
@ -52,7 +53,7 @@ namespace Squidex.Domain.Apps.Core
public bool TryGetItem(string key, out IFieldPartitionItem item)
{
var isFound = string.Equals(key, "iv", StringComparison.OrdinalIgnoreCase);
var isFound = string.Equals(key, Key, StringComparison.OrdinalIgnoreCase);
item = isFound ? this : null;

4
src/Squidex.Domain.Apps.Core.Operations/ConvertContent/FieldConverters.cs

@ -95,7 +95,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
public static FieldConverter ResolveInvariant(LanguagesConfig config)
{
var codeForInvariant = InvariantPartitioning.Instance.Master.Key;
var codeForInvariant = InvariantPartitioning.Key;
var codeForMasterLanguage = config.Master.Language.Iso2Code;
return (data, field) =>
@ -126,7 +126,7 @@ namespace Squidex.Domain.Apps.Core.ConvertContent
public static FieldConverter ResolveLanguages(LanguagesConfig config)
{
var codeForInvariant = InvariantPartitioning.Instance.Master.Key;
var codeForInvariant = InvariantPartitioning.Key;
return (data, field) =>
{

70
src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs

@ -8,15 +8,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Squidex.Domain.Apps.Core.Apps;
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
{
public static class ContentReferencesExtensions
{
public static IEnumerable<Guid> GetReferencedIds(this IdContentData source, Schema schema)
public static IEnumerable<Guid> GetReferencedIds(this IdContentData source, Schema schema, Ids strategy = Ids.All)
{
Guard.NotNull(schema, nameof(schema));
@ -24,7 +27,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
foreach (var field in schema.Fields)
{
var ids = source.GetReferencedIds(field);
var ids = source.GetReferencedIds(field, strategy);
foreach (var id in ids)
{
@ -36,7 +39,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
}
}
public static IEnumerable<Guid> GetReferencedIds(this IdContentData source, IField field)
public static IEnumerable<Guid> GetReferencedIds(this IdContentData source, IField field, Ids strategy = Ids.All)
{
Guard.NotNull(field, nameof(field));
@ -44,7 +47,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
{
foreach (var partitionValue in fieldData)
{
var ids = field.GetReferencedIds(partitionValue.Value);
var ids = field.GetReferencedIds(partitionValue.Value, strategy);
foreach (var id in ids)
{
@ -54,7 +57,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
}
}
public static IEnumerable<Guid> GetReferencedIds(this NamedContentData source, IField field)
public static IEnumerable<Guid> GetReferencedIds(this NamedContentData source, IField field, Ids strategy = Ids.All)
{
Guard.NotNull(field, nameof(field));
@ -62,7 +65,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
{
foreach (var partitionValue in fieldData)
{
var ids = field.GetReferencedIds(partitionValue.Value);
var ids = field.GetReferencedIds(partitionValue.Value, strategy);
foreach (var id in ids)
{
@ -71,5 +74,60 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
}
}
}
public static JsonObject FormatReferences(this NamedContentData data, Schema schema, LanguagesConfig languages, string separator = ", ")
{
Guard.NotNull(schema, nameof(schema));
var result = JsonValue.Object();
foreach (var language in languages)
{
result[language.Key] = JsonValue.Create(data.FormatReferenceFields(schema, language.Key, separator));
}
return result;
}
private static string FormatReferenceFields(this NamedContentData data, Schema schema, string partition, string separator)
{
Guard.NotNull(schema, nameof(schema));
var sb = new StringBuilder();
void AddValue(object value)
{
if (sb.Length > 0)
{
sb.Append(separator);
}
sb.Append(value);
}
var referenceFields = schema.Fields.Where(x => x.RawProperties.IsReferenceField);
if (!referenceFields.Any())
{
referenceFields = schema.Fields.Take(1);
}
foreach (var referenceField in referenceFields)
{
if (data.TryGetValue(referenceField.Name, out var fieldData))
{
if (fieldData.TryGetValue(partition, out var value))
{
AddValue(value);
}
else if (fieldData.TryGetValue(InvariantPartitioning.Key, out var value2))
{
AddValue(value2);
}
}
}
return sb.ToString();
}
}
}

15
src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/Ids.cs

@ -0,0 +1,15 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
{
public enum Ids
{
All,
ContentOnly
}
}

5
src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtensions.cs

@ -7,7 +7,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure.Json.Objects;
@ -15,9 +14,9 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
{
public static class ReferencesExtensions
{
public static IEnumerable<Guid> GetReferencedIds(this IField field, IJsonValue value)
public static IEnumerable<Guid> GetReferencedIds(this IField field, IJsonValue value, Ids strategy = Ids.All)
{
return ReferencesExtractor.ExtractReferences(field, value);
return ReferencesExtractor.ExtractReferences(field, value, strategy);
}
public static IJsonValue CleanReferences(this IField field, IJsonValue value, ICollection<Guid> oldReferences)

13
src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesExtractor.cs

@ -16,15 +16,18 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
public sealed class ReferencesExtractor : IFieldVisitor<IEnumerable<Guid>>
{
private readonly IJsonValue value;
private readonly Ids strategy;
private ReferencesExtractor(IJsonValue value)
private ReferencesExtractor(IJsonValue value, Ids strategy)
{
this.value = value;
this.strategy = strategy;
}
public static IEnumerable<Guid> ExtractReferences(IField field, IJsonValue value)
public static IEnumerable<Guid> ExtractReferences(IField field, IJsonValue value, Ids strategy)
{
return field.Accept(new ReferencesExtractor(value));
return field.Accept(new ReferencesExtractor(value, strategy));
}
public IEnumerable<Guid> Visit(IArrayField field)
@ -39,7 +42,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
{
if (item.TryGetValue(nestedField.Name, out var nestedValue))
{
result.AddRange(nestedField.Accept(new ReferencesExtractor(nestedValue)));
result.AddRange(nestedField.Accept(new ReferencesExtractor(nestedValue, strategy)));
}
}
}
@ -59,7 +62,7 @@ namespace Squidex.Domain.Apps.Core.ExtractReferenceIds
{
var ids = value.ToGuidSet();
if (field.Properties.SchemaId != Guid.Empty)
if (strategy == Ids.All && field.Properties.SchemaId != Guid.Empty)
{
ids.Add(field.Properties.SchemaId);
}

2
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ObjectPath.cs

@ -26,7 +26,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
}
else if (index == 1)
{
if (!property.Equals(InvariantPartitioning.Instance.Master.Key, StringComparison.OrdinalIgnoreCase))
if (!property.Equals(InvariantPartitioning.Key, StringComparison.OrdinalIgnoreCase))
{
sb.Append("(");
sb.Append(property);

2
src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/UniqueValidator.cs

@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{
var count = context.Path.Count();
if (value != null && (count == 0 || (count == 2 && context.Path.Last() == InvariantPartitioning.Instance.Master.Key)))
if (value != null && (count == 0 || (count == 2 && context.Path.Last() == InvariantPartitioning.Key)))
{
FilterNode filter = null;

4
src/Squidex.Domain.Apps.Entities/Apps/Templates/CreateProfileCommandMiddleware.cs

@ -150,7 +150,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates
private static async Task<NamedId<Guid>> CreateExperienceSchemaAsync(Func<ICommand, Task> publish)
{
var schema =
SchemaBuilder.Create("experience")
SchemaBuilder.Create("Experience")
.AddString("Position", f => f
.Required()
.ShowInList()
@ -177,7 +177,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.Templates
private static async Task<NamedId<Guid>> CreateEducationSchemaAsync(Func<ICommand, Task> publish)
{
var schema =
SchemaBuilder.Create("Experience")
SchemaBuilder.Create("Education")
.AddString("Degree", f => f
.Required()
.ShowInList()

9
src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs

@ -17,22 +17,25 @@ namespace Squidex.Domain.Apps.Entities.Contents
public sealed class ContentCommandMiddleware : GrainCommandMiddleware<ContentCommand, IContentGrain>
{
private readonly IContentEnricher contentEnricher;
private readonly IContextProvider contextProvider;
public ContentCommandMiddleware(IGrainFactory grainFactory, IContentEnricher contentEnricher)
public ContentCommandMiddleware(IGrainFactory grainFactory, IContentEnricher contentEnricher, IContextProvider contextProvider)
: base(grainFactory)
{
Guard.NotNull(contentEnricher, nameof(contentEnricher));
Guard.NotNull(contextProvider, nameof(contextProvider));
this.contentEnricher = contentEnricher;
this.contextProvider = contextProvider;
}
public override async Task HandleAsync(CommandContext context, Func<Task> next)
{
await base.HandleAsync(context, next);
if (context.Command is SquidexCommand command && context.PlainResult is IContentEntity content && NotEnriched(context))
if (context.PlainResult is IContentEntity content && NotEnriched(context))
{
var enriched = await contentEnricher.EnrichAsync(content, command.User);
var enriched = await contentEnricher.EnrichAsync(content, contextProvider.Context);
context.Complete(enriched);
}

115
src/Squidex.Domain.Apps.Entities/Contents/ContentEnricher.cs

@ -8,7 +8,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.ExtractReferenceIds;
@ -23,41 +22,37 @@ 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 static readonly Dictionary<Guid, IEnrichedContentEntity> EmptyReferences = new Dictionary<Guid, IEnrichedContentEntity>();
private readonly Lazy<IContentQueryService> contentQuery;
private readonly IContentWorkflow contentWorkflow;
private readonly IContextProvider contextProvider;
public ContentEnricher(
IAppProvider appProvider,
IContentQueryService contentQuery,
IContentWorkflow contentWorkflow,
IContextProvider contextProvider)
private IContentQueryService ContentQuery
{
get { return contentQuery.Value; }
}
public ContentEnricher(Lazy<IContentQueryService> contentQuery, IContentWorkflow contentWorkflow)
{
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;
}
public async Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, ClaimsPrincipal user)
public async Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, Context context)
{
Guard.NotNull(content, nameof(content));
var enriched = await EnrichAsync(Enumerable.Repeat(content, 1), user);
var enriched = await EnrichAsync(Enumerable.Repeat(content, 1), context);
return enriched[0];
}
public async Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, ClaimsPrincipal user)
public async Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, Context context)
{
Guard.NotNull(contents, nameof(contents));
Guard.NotNull(user, nameof(user));
Guard.NotNull(context, nameof(context));
using (Profiler.TraceMethod<ContentEnricher>())
{
@ -73,20 +68,20 @@ namespace Squidex.Domain.Apps.Entities.Contents
await ResolveColorAsync(content, result, cache);
if (ShouldEnrichWithStatuses())
if (ShouldEnrichWithStatuses(context))
{
await ResolveNextsAsync(content, result, user);
await ResolveNextsAsync(content, result, context);
await ResolveCanUpdateAsync(content, result);
}
results.Add(result);
}
if (contextProvider.Context.IsFrontendClient)
if (ShouldEnrichWithReferences(context))
{
foreach (var group in results.GroupBy(x => x.SchemaId))
foreach (var group in results.GroupBy(x => x.SchemaId.Id))
{
await ResolveReferencesAsync(group.Key, group);
await ResolveReferencesAsync(group.Key, group, context);
}
}
}
@ -95,67 +90,85 @@ namespace Squidex.Domain.Apps.Entities.Contents
}
}
private async Task ResolveReferencesAsync(NamedId<Guid> schemaId, IEnumerable<ContentEntity> contents)
private async Task ResolveReferencesAsync(Guid schemaId, IEnumerable<ContentEntity> contents, Context context)
{
var appId = contents.First().AppId.Id;
var schema = await appProvider.GetSchemaAsync(appId, schemaId.Id);
var schema = await ContentQuery.GetSchemaOrThrowAsync(context, schemaId.ToString());
var referenceFields =
schema.SchemaDef.Fields.OfType<IField<ReferencesFieldProperties>>()
.Where(x =>
x.Properties.SchemaId != Guid.Empty &&
x.Properties.MinItems == 1 &&
x.Properties.MaxItems == 1 &&
(x.Properties.IsListField || x.Properties.IsReferenceField));
x.Properties.IsListField);
var formatted = new Dictionary<Guid, JsonObject>();
foreach (var field in referenceFields)
{
var allIds = GetContentIds(contents, field);
foreach (var content in contents)
{
content.ReferenceData = new NamedContentData();
content.ReferenceData.GetOrAddNew(field.Name);
}
if (allIds.Count > 0)
try
{
var referenced = await contentQuery.QueryAsync(contextProvider.Context, schemaId.Id.ToString(), Q.Empty.WithIds(allIds));
var referencedSchemaId = field.Properties.SchemaId;
var referencedSchema = await ContentQuery.GetSchemaOrThrowAsync(context, referencedSchemaId.ToString());
var byId = referenced.ToDictionary(x => x.Id);
var references = await GetReferencesAsync(referencedSchemaId, contents, field, context);
foreach (var content in contents)
{
content.ReferenceData = content.ReferenceData ?? new NamedContentData();
var fieldReference = content.ReferenceData[field.Name];
if (content.DataDraft.TryGetValue(field.Name, out var fieldData))
{
foreach (var partitionValue in fieldData.Where(x => x.Value.Type != JsonValueType.Null))
foreach (var partition in fieldData)
{
var ids = field.GetReferencedIds(partitionValue.Value).ToArray();
var id = field.GetReferencedIds(partition.Value, Ids.ContentOnly).FirstOrDefault();
if (ids.Length == 1)
if (references.TryGetValue(id, out var reference))
{
if (byId.TryGetValue(ids[0], out var reference))
{
}
var value =
formatted.GetOrAdd(id,
_ => reference.DataDraft.FormatReferences(referencedSchema.SchemaDef, context.App.LanguagesConfig));
fieldReference[partition.Key] = JsonValue.Create(value);
}
}
}
}
}
catch (DomainObjectNotFoundException)
{
continue;
}
}
}
private static HashSet<Guid> GetContentIds(IEnumerable<ContentEntity> contents, IField<ReferencesFieldProperties> field)
private async Task<Dictionary<Guid, IEnrichedContentEntity>> GetReferencesAsync(Guid schemaId, IEnumerable<ContentEntity> contents, IField field, Context context)
{
var allIds = new HashSet<Guid>();
var ids = new HashSet<Guid>();
foreach (var content in contents)
{
allIds.AddRange(content.DataDraft.GetReferencedIds(field));
ids.AddRange(content.DataDraft.GetReferencedIds(field, Ids.ContentOnly));
}
return allIds;
}
if (ids.Count > 0)
{
var references = await ContentQuery.QueryAsync(context.Clone().WithNoEnrichment(true), schemaId.ToString(), Q.Empty.WithIds(ids));
private bool ShouldEnrichWithStatuses()
{
return contextProvider.Context.IsFrontendClient || contextProvider.Context.IsResolveFlow();
return references.ToDictionary(x => x.Id);
}
else
{
return EmptyReferences;
}
}
private async Task ResolveCanUpdateAsync(IContentEntity content, ContentEntity result)
@ -163,9 +176,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
result.CanUpdate = await contentWorkflow.CanUpdateAsync(content);
}
private async Task ResolveNextsAsync(IContentEntity content, ContentEntity result, ClaimsPrincipal user)
private async Task ResolveNextsAsync(IContentEntity content, ContentEntity result, Context context)
{
result.Nexts = await contentWorkflow.GetNextsAsync(content, user);
result.Nexts = await contentWorkflow.GetNextsAsync(content, context.User);
}
private async Task ResolveColorAsync(IContentEntity content, ContentEntity result, Dictionary<(Guid, Status), StatusInfo> cache)
@ -189,5 +202,15 @@ namespace Squidex.Domain.Apps.Entities.Contents
return info.Color;
}
private static bool ShouldEnrichWithStatuses(Context context)
{
return context.IsFrontendClient || context.IsResolveFlow();
}
private static bool ShouldEnrichWithReferences(Context context)
{
return context.IsFrontendClient && !context.IsNoEnrichment();
}
}
}

2
src/Squidex.Domain.Apps.Entities/Contents/ContentQueryService.cs

@ -186,7 +186,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var scriptText = schema.SchemaDef.Scripts.Query;
var scripting = !string.IsNullOrWhiteSpace(scriptText);
var enriched = await contentEnricher.EnrichAsync(contents, context.User);
var enriched = await contentEnricher.EnrichAsync(contents, context);
foreach (var content in enriched)
{

5
src/Squidex.Domain.Apps.Entities/Contents/IContentEnricher.cs

@ -6,15 +6,14 @@
// ==========================================================================
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Squidex.Domain.Apps.Entities.Contents
{
public interface IContentEnricher
{
Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, ClaimsPrincipal user);
Task<IEnrichedContentEntity> EnrichAsync(IContentEntity content, Context context);
Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, ClaimsPrincipal user);
Task<IReadOnlyList<IEnrichedContentEntity>> EnrichAsync(IEnumerable<IContentEntity> contents, Context context);
}
}

2
src/Squidex.Domain.Apps.Entities/Contents/IEnrichedContentEntity.cs

@ -16,5 +16,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
string StatusColor { get; }
StatusInfo[] Nexts { get; }
NamedContentData ReferenceData { get; }
}
}

2
src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexerGrain.cs

@ -31,7 +31,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
private static readonly TimeSpan CommitDelay = TimeSpan.FromSeconds(10);
private static readonly MergeScheduler MergeScheduler = new ConcurrentMergeScheduler();
private static readonly Analyzer Analyzer = new MultiLanguageAnalyzer(Version);
private static readonly string[] Invariant = { InvariantPartitioning.Instance.Master.Key };
private static readonly string[] Invariant = { InvariantPartitioning.Key };
private readonly SnapshotDeletionPolicy snapshotter = new SnapshotDeletionPolicy(new KeepOnlyLastCommitDeletionPolicy());
private readonly IAssetStore assetStore;
private IDisposable timer;

1
src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs

@ -14,7 +14,6 @@ using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Apps.Services;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Security;
using Squidex.Shared;

1
src/Squidex/Areas/Api/Controllers/Apps/Models/ContributorsDto.cs

@ -10,7 +10,6 @@ using System.Linq;
using Newtonsoft.Json;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Apps.Services;
using Squidex.Infrastructure;
using Squidex.Shared;
using Squidex.Web;

5
src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs

@ -49,6 +49,11 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models
/// </summary>
public object DataDraft { get; set; }
/// <summary>
/// The reference data for the frontend UI.
/// </summary>
public NamedContentData ReferenceData { get; set; }
/// <summary>
/// Indicates if the draft data is pending.
/// </summary>

1
src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs

@ -8,7 +8,6 @@
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Domain.Apps.Entities.Schemas;

1
src/Squidex/Areas/Api/Controllers/History/HistoryController.cs

@ -10,7 +10,6 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Squidex.Areas.Api.Controllers.History.Models;
using Squidex.Domain.Apps.Entities.History;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Shared;
using Squidex.Web;

1
src/Squidex/Areas/Api/Controllers/Schemas/Models/SchemasDto.cs

@ -8,7 +8,6 @@
using System.Collections.Generic;
using System.Linq;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
using Squidex.Shared;
using Squidex.Web;

3
src/Squidex/Config/Domain/EntitiesServices.cs

@ -105,6 +105,9 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<ContentEnricher>()
.As<IContentEnricher>();
services.AddSingletonAs(c => new Lazy<IContentEnricher>(() => c.GetRequiredService<IContentEnricher>()))
.AsSelf();
services.AddSingletonAs<ContentQueryService>()
.As<IContentQueryService>();

30
src/Squidex/app/features/content/shared/content-item.component.ts

@ -13,13 +13,11 @@ import {
ContentsState,
fadeAnimation,
FieldDto,
FieldFormatter,
fieldInvariant,
getContentValue,
ModalModel,
PatchContentForm,
RootFieldDto,
SchemaDetailsDto,
Types
SchemaDetailsDto
} from '@app/shared';
/* tslint:disable:component-selector */
@ -152,13 +150,9 @@ export class ContentItemComponent implements OnChanges {
this.values = [];
for (let field of this.schemaFields) {
const value = this.getRawValue(field);
const { value, formatted } = getContentValue(this.content, this.language, field);
if (Types.isUndefined(value)) {
this.values.push('');
} else {
this.values.push(FieldFormatter.format(field, value, true));
}
this.values.push(formatted);
if (this.patchForm) {
const formControl = this.patchForm.form.controls[field.name];
@ -170,21 +164,7 @@ export class ContentItemComponent implements OnChanges {
}
}
private getRawValue(field: RootFieldDto): any {
const contentField = this.content.dataDraft[field.name];
if (contentField) {
if (field.isLocalizable) {
return contentField[this.language.iso2Code];
} else {
return contentField[fieldInvariant];
}
}
return undefined;
}
public trackByField(index: number, field: FieldDto) {
public trackByField(field: FieldDto) {
return field.fieldId + this.schema.id;
}
}

34
src/Squidex/app/features/content/shared/references-dropdown.component.ts

@ -15,11 +15,9 @@ import {
AppsState,
ContentDto,
ContentsService,
FieldFormatter,
fieldInvariant,
getContentValue,
ImmutableArray,
MathHelper,
RootFieldDto,
SchemaDetailsDto,
SchemasService,
StatefulControlComponent,
@ -125,32 +123,12 @@ export class ReferencesDropdownComponent extends StatefulControlComponent<State,
return ImmutableArray.empty();
}
function getRawValue(field: RootFieldDto, data: any, language: AppLanguageDto): any {
const contentField = data[field.name];
if (contentField) {
if (field.isLocalizable) {
return contentField[language.iso2Code];
} else {
return contentField[fieldInvariant];
}
}
return undefined;
}
return contents.map(content => {
const values: any[] = [];
for (let field of schema.referenceFields) {
const value = getRawValue(field, content.data, this.languageField);
if (!Types.isUndefined(value)) {
values.push(FieldFormatter.format(field, value, false));
}
}
const name = values.join(', ');
const name =
schema.referenceFields
.map(f => getContentValue(content, this.languageField, f, false))
.map(v => v.formatted)
.join(', ');
return { name, id: content.id };
});

2
src/Squidex/app/shared/services/contents.service.spec.ts

@ -366,6 +366,7 @@ describe('ContentsService', () => {
isPending: true,
data: {},
dataDraft: {},
referenceData: {},
version: `${id}`,
_links: {
update: { method: 'PUT', href: `/contents/id${id}` }
@ -389,5 +390,6 @@ export function createContent(id: number, suffix = '') {
true,
{},
{},
{},
new Version(`${id}`));
}

11
src/Squidex/app/shared/services/contents.service.ts

@ -55,6 +55,11 @@ export class ContentsDto extends ResultSet<ContentDto> {
}
}
export type ContentReferencesValue = { [partition: string]: string };
export type ContentReferences = { [fieldName: string ]: ContentFieldData<ContentReferencesValue> };
export type ContentFieldData<T = any> = { [partition: string]: T };
export type ContentData = { [fieldName: string ]: ContentFieldData };
export class ContentDto {
public readonly _links: ResourceLinks;
@ -77,8 +82,9 @@ export class ContentDto {
public readonly lastModifiedBy: string,
public readonly scheduleJob: ScheduleDto | null,
public readonly isPending: boolean,
public readonly data: object | any,
public readonly dataDraft: object,
public readonly data: ContentData | undefined,
public readonly dataDraft: ContentData,
public readonly referenceData: ContentReferences,
public readonly version: Version
) {
this._links = links;
@ -299,5 +305,6 @@ function parseContent(response: any) {
response.isPending === true,
response.data,
response.dataDraft,
response.referenceData,
new Version(response.version.toString()));
}

102
src/Squidex/app/shared/state/contents.forms.ts

@ -19,6 +19,8 @@ import {
value$
} from '@app/framework';
import { ContentDto, ContentReferencesValue } from '../services/contents.service';
import { LanguageDto } from '../services/languages.service';
import { AppLanguageDto } from './../services/app-languages.service';
import { FieldDto, RootFieldDto, SchemaDetailsDto } from './../services/schemas.service';
import {
@ -56,7 +58,55 @@ export class SaveQueryForm extends Form<FormGroup, any> {
}
}
export class FieldFormatter implements FieldPropertiesVisitor<any> {
export type FieldValue = string | HtmlValue;
export function getContentValue(content: ContentDto, language: LanguageDto, field: RootFieldDto, allowHtml = true): { value: any, formatted: FieldValue } {
const reference = content.referenceData[field.name];
if (reference) {
let fieldValue: ContentReferencesValue;
if (field.isLocalizable) {
fieldValue = reference[language.iso2Code];
} else {
fieldValue = reference[fieldInvariant];
}
let value = '';
if (fieldValue) {
value = fieldValue[language.iso2Code] || '';
}
return { value, formatted: value };
}
const contentField = content.dataDraft[field.name];
if (contentField) {
let value: any;
if (field.isLocalizable) {
value = contentField[language.iso2Code];
} else {
value = contentField[fieldInvariant];
}
let formatted: any;
if (Types.isUndefined(value)) {
formatted = value || '';
} else {
formatted = FieldFormatter.format(field, value, allowHtml);
}
return { value, formatted };
}
return { value: undefined, formatted: '' };
}
export class FieldFormatter implements FieldPropertiesVisitor<FieldValue> {
constructor(
private readonly value: any,
private readonly allowHtml: boolean
@ -71,7 +121,7 @@ export class FieldFormatter implements FieldPropertiesVisitor<any> {
return field.properties.accept(new FieldFormatter(value, allowHtml));
}
public visitDateTime(properties: DateTimeFieldPropertiesDto): string | any {
public visitDateTime(properties: DateTimeFieldPropertiesDto): FieldValue {
try {
const parsed = DateTime.parseISO_UTC(this.value);
@ -85,7 +135,7 @@ export class FieldFormatter implements FieldPropertiesVisitor<any> {
}
}
public visitArray(properties: ArrayFieldPropertiesDto): string {
public visitArray(_: ArrayFieldPropertiesDto): string {
if (this.value.length) {
return `${this.value.length} Item(s)`;
} else {
@ -93,7 +143,7 @@ export class FieldFormatter implements FieldPropertiesVisitor<any> {
}
}
public visitAssets(properties: AssetsFieldPropertiesDto): string {
public visitAssets(_: AssetsFieldPropertiesDto): string {
if (this.value.length) {
return `${this.value.length} Asset(s)`;
} else {
@ -101,7 +151,7 @@ export class FieldFormatter implements FieldPropertiesVisitor<any> {
}
}
public visitReferences(properties: ReferencesFieldPropertiesDto): string {
public visitReferences(_: ReferencesFieldPropertiesDto): string {
if (this.value.length) {
return `${this.value.length} Reference(s)`;
} else {
@ -109,7 +159,7 @@ export class FieldFormatter implements FieldPropertiesVisitor<any> {
}
}
public visitTags(properties: TagsFieldPropertiesDto): string {
public visitTags(_: TagsFieldPropertiesDto): string {
if (this.value.length) {
return this.value.join(', ');
} else {
@ -117,19 +167,19 @@ export class FieldFormatter implements FieldPropertiesVisitor<any> {
}
}
public visitBoolean(properties: BooleanFieldPropertiesDto): string {
public visitBoolean(_: BooleanFieldPropertiesDto): string {
return this.value ? 'Yes' : 'No';
}
public visitGeolocation(properties: GeolocationFieldPropertiesDto): string {
public visitGeolocation(_: GeolocationFieldPropertiesDto): string {
return `${this.value.longitude}, ${this.value.latitude}`;
}
public visitJson(properties: JsonFieldPropertiesDto): string {
public visitJson(_: JsonFieldPropertiesDto): string {
return '<Json />';
}
public visitNumber(properties: NumberFieldPropertiesDto): string | HtmlValue | number {
public visitNumber(properties: NumberFieldPropertiesDto): FieldValue {
if (Types.isNumber(this.value) && properties.editor === 'Stars' && this.allowHtml) {
if (this.value <= 0 || this.value > 6) {
return new HtmlValue(`&#9733; ${this.value}`);
@ -143,15 +193,15 @@ export class FieldFormatter implements FieldPropertiesVisitor<any> {
return new HtmlValue(html);
}
}
return this.value;
return `${this.value}`;
}
public visitString(properties: StringFieldPropertiesDto): any {
public visitString(_: StringFieldPropertiesDto): any {
return this.value;
}
public visitUI(properties: UIFieldPropertiesDto): any {
return this.value;
public visitUI(_: UIFieldPropertiesDto): any {
return '';
}
}
@ -257,23 +307,23 @@ export class FieldValidatorsFactory implements FieldPropertiesVisitor<ValidatorF
return validators;
}
public visitBoolean(properties: BooleanFieldPropertiesDto): ValidatorFn[] {
public visitBoolean(_: BooleanFieldPropertiesDto): ValidatorFn[] {
return [];
}
public visitDateTime(properties: DateTimeFieldPropertiesDto): ValidatorFn[] {
public visitDateTime(_: DateTimeFieldPropertiesDto): ValidatorFn[] {
return [];
}
public visitGeolocation(properties: GeolocationFieldPropertiesDto): ValidatorFn[] {
public visitGeolocation(_: GeolocationFieldPropertiesDto): ValidatorFn[] {
return [];
}
public visitJson(properties: JsonFieldPropertiesDto): ValidatorFn[] {
public visitJson(_: JsonFieldPropertiesDto): ValidatorFn[] {
return [];
}
public visitUI(properties: UIFieldPropertiesDto): ValidatorFn[] {
public visitUI(_: UIFieldPropertiesDto): ValidatorFn[] {
return [];
}
}
@ -300,11 +350,11 @@ export class FieldDefaultValue implements FieldPropertiesVisitor<any> {
return field.properties.accept(new FieldDefaultValue(now));
}
public visitArray(properties: ArrayFieldPropertiesDto): any {
public visitArray(_: ArrayFieldPropertiesDto): any {
return null;
}
public visitAssets(properties: AssetsFieldPropertiesDto): any {
public visitAssets(_: AssetsFieldPropertiesDto): any {
return null;
}
@ -312,11 +362,11 @@ export class FieldDefaultValue implements FieldPropertiesVisitor<any> {
return properties.defaultValue;
}
public visitGeolocation(properties: GeolocationFieldPropertiesDto): any {
public visitGeolocation(_: GeolocationFieldPropertiesDto): any {
return null;
}
public visitJson(properties: JsonFieldPropertiesDto): any {
public visitJson(_: JsonFieldPropertiesDto): any {
return null;
}
@ -324,7 +374,7 @@ export class FieldDefaultValue implements FieldPropertiesVisitor<any> {
return properties.defaultValue;
}
public visitReferences(properties: ReferencesFieldPropertiesDto): any {
public visitReferences(_: ReferencesFieldPropertiesDto): any {
return null;
}
@ -332,11 +382,11 @@ export class FieldDefaultValue implements FieldPropertiesVisitor<any> {
return properties.defaultValue;
}
public visitTags(properties: TagsFieldPropertiesDto): any {
public visitTags(_: TagsFieldPropertiesDto): any {
return null;
}
public visitUI(properties: UIFieldPropertiesDto): any {
public visitUI(_: UIFieldPropertiesDto): any {
return null;
}
}

2
src/Squidex/appsettings.json

@ -296,7 +296,7 @@
*
* Supported: MongoDB, Development
*/
"clustering": "Development",
"clustering": "MongoDB",
/*
* The port is used to share messages between all cluster members. Must be accessible within your cluster or network.
*/

14
tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceExtractionTests.cs

@ -194,6 +194,20 @@ namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds
Assert.Equal(new[] { id1, id2, schemaId }, result);
}
[Fact]
public void Should_return_ids_from_references_field_without_schema_id()
{
var id1 = Guid.NewGuid();
var id2 = Guid.NewGuid();
var sut = Fields.References(1, "my-refs", Partitioning.Invariant,
new ReferencesFieldProperties { SchemaId = schemaId });
var result = sut.GetReferencedIds(CreateValue(id1, id2), Ids.ContentOnly).ToArray();
Assert.Equal(new[] { id1, id2 }, result);
}
[Fact]
public void Should_return_list_from_references_field_with_schema_id_list_for_referenced_ids_when_null()
{

81
tests/Squidex.Domain.Apps.Core.Tests/Operations/ExtractReferenceIds/ReferenceFormattingTests.cs

@ -0,0 +1,81 @@
// ==========================================================================
// 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.ExtractReferenceIds;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects;
using Xunit;
namespace Squidex.Domain.Apps.Core.Operations.ExtractReferenceIds
{
public class ReferenceFormattingTests
{
private readonly LanguagesConfig languages = LanguagesConfig.English.Set(Language.DE);
[Fact]
public void Should_format_data_with_reference_fields()
{
var data = CreateData();
var schema =
new Schema("my-schema")
.AddString(1, "ref1", Partitioning.Invariant,
new StringFieldProperties { IsReferenceField = true })
.AddString(2, "ref2", Partitioning.Invariant,
new StringFieldProperties { IsReferenceField = true })
.AddString(3, "non-ref", Partitioning.Invariant);
var formatted = data.FormatReferences(schema, languages);
var expected =
JsonValue.Object()
.Add("en", "EN, 12")
.Add("de", "DE, 12");
Assert.Equal(expected, formatted);
}
[Fact]
public void Should_format_data_with_first_field_if_no_reference_field_defined()
{
var data = CreateData();
var schema =
new Schema("my-schema")
.AddString(1, "ref1", Partitioning.Invariant)
.AddString(2, "ref2", Partitioning.Invariant)
.AddString(3, "non-ref", Partitioning.Invariant);
var formatted = data.FormatReferences(schema, languages);
var expected =
JsonValue.Object()
.Add("en", "EN")
.Add("de", "DE");
Assert.Equal(expected, formatted);
}
private static NamedContentData CreateData()
{
return new NamedContentData()
.AddField("ref1",
new ContentFieldData()
.AddValue("en", "EN")
.AddValue("de", "DE"))
.AddField("ref2",
new ContentFieldData()
.AddValue("iv", 12))
.AddField("non-ref",
new ContentFieldData()
.AddValue("iv", "Ignored"));
}
}
}

13
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs

@ -19,7 +19,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
public sealed class ContentCommandMiddlewareTests : HandlerTestBase<ContentState>
{
private readonly IContentEnricher contentEnricher = A.Fake<IContentEnricher>();
private readonly IContextProvider contextProvider = A.Fake<IContextProvider>();
private readonly Guid contentId = Guid.NewGuid();
private readonly Context requestContext = new Context();
private readonly ContentCommandMiddleware sut;
public sealed class MyCommand : SquidexCommand
@ -33,7 +35,10 @@ namespace Squidex.Domain.Apps.Entities.Contents
public ContentCommandMiddlewareTests()
{
sut = new ContentCommandMiddleware(A.Fake<IGrainFactory>(), contentEnricher);
A.CallTo(() => contextProvider.Context)
.Returns(requestContext);
sut = new ContentCommandMiddleware(A.Fake<IGrainFactory>(), contentEnricher, contextProvider);
}
[Fact]
@ -46,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
await sut.HandleAsync(context);
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>.Ignored, User))
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>.Ignored, requestContext))
.MustNotHaveHappened();
}
@ -64,7 +69,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
Assert.Same(result, context.Result<IEnrichedContentEntity>());
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>.Ignored, User))
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnrichedContentEntity>.Ignored, requestContext))
.MustNotHaveHappened();
}
@ -80,7 +85,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
var enriched = new ContentEntity();
A.CallTo(() => contentEnricher.EnrichAsync(result, User))
A.CallTo(() => contentEnricher.EnrichAsync(result, requestContext))
.Returns(enriched);
await sut.HandleAsync(context);

25
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEnricherTests.cs

@ -6,7 +6,6 @@
// ==========================================================================
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Core.Contents;
@ -18,18 +17,14 @@ namespace Squidex.Domain.Apps.Entities.Contents
public class ContentEnricherTests
{
private readonly IContentWorkflow contentWorkflow = A.Fake<IContentWorkflow>();
private readonly IContextProvider contextProvider = A.Fake<IContextProvider>();
private readonly ClaimsPrincipal user = new ClaimsPrincipal();
private readonly Context context = new Context();
private readonly IContentQueryService contentQuery = A.Fake<IContentQueryService>();
private readonly Context requestContext = new Context();
private readonly NamedId<Guid> schemaId = NamedId.Of(Guid.NewGuid(), "my-schema");
private readonly ContentEnricher sut;
public ContentEnricherTests()
{
A.CallTo(() => contextProvider.Context)
.Returns(context);
sut = new ContentEnricher(contentWorkflow, contextProvider);
sut = new ContentEnricher(new Lazy<IContentQueryService>(() => contentQuery), contentWorkflow);
}
[Fact]
@ -40,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => contentWorkflow.GetInfoAsync(source))
.Returns(new StatusInfo(Status.Published, StatusColors.Published));
var result = await sut.EnrichAsync(source, user);
var result = await sut.EnrichAsync(source, requestContext);
Assert.Equal(StatusColors.Published, result.StatusColor);
}
@ -53,7 +48,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => contentWorkflow.GetInfoAsync(source))
.Returns(Task.FromResult<StatusInfo>(null));
var result = await sut.EnrichAsync(source, user);
var result = await sut.EnrichAsync(source, requestContext);
Assert.Equal(StatusColors.Draft, result.StatusColor);
}
@ -61,14 +56,14 @@ namespace Squidex.Domain.Apps.Entities.Contents
[Fact]
public async Task Should_enrich_content_with_can_update()
{
context.WithResolveFlow(true);
requestContext.WithResolveFlow(true);
var source = new ContentEntity { SchemaId = schemaId };
A.CallTo(() => contentWorkflow.CanUpdateAsync(source))
.Returns(true);
var result = await sut.EnrichAsync(source, user);
var result = await sut.EnrichAsync(source, requestContext);
Assert.True(result.CanUpdate);
}
@ -76,11 +71,11 @@ namespace Squidex.Domain.Apps.Entities.Contents
[Fact]
public async Task Should_not_enrich_content_with_can_update_if_disabled_in_context()
{
context.WithResolveFlow(false);
requestContext.WithResolveFlow(false);
var source = new ContentEntity { SchemaId = schemaId };
var result = await sut.EnrichAsync(source, user);
var result = await sut.EnrichAsync(source, requestContext);
Assert.False(result.CanUpdate);
@ -97,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => contentWorkflow.GetInfoAsync(source1))
.Returns(new StatusInfo(Status.Published, StatusColors.Published));
var result = await sut.EnrichAsync(new[] { source1, source2 }, user);
var result = await sut.EnrichAsync(new[] { source1, source2 }, requestContext);
Assert.Equal(StatusColors.Published, result[0].StatusColor);
Assert.Equal(StatusColors.Published, result[1].StatusColor);

2
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentQueryServiceTests.cs

@ -527,7 +527,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
private void SetupEnricher()
{
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnumerable<IContentEntity>>.Ignored, user))
A.CallTo(() => contentEnricher.EnrichAsync(A<IEnumerable<IContentEntity>>.Ignored, context))
.ReturnsLazily(x =>
{
var input = (IEnumerable<IContentEntity>)x.Arguments[0];

Loading…
Cancel
Save