Browse Source

Exception handling for content validation.

pull/579/head
Sebastian 5 years ago
parent
commit
c517c272dd
  1. 1
      backend/i18n/source/backend_en.json
  2. 9
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs
  3. 14
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs
  4. 25
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AggregateValidator.cs
  5. 35
      backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs
  6. 12
      backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs
  7. 3
      backend/src/Squidex.Shared/Texts.it.resx
  8. 3
      backend/src/Squidex.Shared/Texts.nl.resx
  9. 3
      backend/src/Squidex.Shared/Texts.resx
  10. 66
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs
  11. 49
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs
  12. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs

1
backend/i18n/source/backend_en.json

@ -147,6 +147,7 @@
"contents.validation.characterCount": "Must have exactly {count} character(s).", "contents.validation.characterCount": "Must have exactly {count} character(s).",
"contents.validation.charactersBetween": "Must have between {min} and {max} character(s).", "contents.validation.charactersBetween": "Must have between {min} and {max} character(s).",
"contents.validation.duplicates": "Must not contain duplicate values.", "contents.validation.duplicates": "Must not contain duplicate values.",
"contents.validation.error": "Validation failed with internal error.",
"contents.validation.exactValue": "Must be exactly {value}.", "contents.validation.exactValue": "Must be exactly {value}.",
"contents.validation.extension": "Must be an allowed extension.", "contents.validation.extension": "Must be an allowed extension.",
"contents.validation.image": "Not an image.", "contents.validation.image": "Not an image.",

9
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs

@ -14,6 +14,7 @@ using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.ValidateContent.Validators; using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
#pragma warning disable SA1028, IDE0004 // Code must not contain trailing whitespace #pragma warning disable SA1028, IDE0004 // Code must not contain trailing whitespace
@ -25,6 +26,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
private readonly PartitionResolver partitionResolver; private readonly PartitionResolver partitionResolver;
private readonly ValidationContext context; private readonly ValidationContext context;
private readonly IEnumerable<IValidatorsFactory> factories; private readonly IEnumerable<IValidatorsFactory> factories;
private readonly ISemanticLog log;
private readonly ConcurrentBag<ValidationError> errors = new ConcurrentBag<ValidationError>(); private readonly ConcurrentBag<ValidationError> errors = new ConcurrentBag<ValidationError>();
public IReadOnlyCollection<ValidationError> Errors public IReadOnlyCollection<ValidationError> Errors
@ -32,7 +34,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
get { return errors; } get { return errors; }
} }
public ContentValidator(PartitionResolver partitionResolver, ValidationContext context, IEnumerable<IValidatorsFactory> factories) public ContentValidator(PartitionResolver partitionResolver, ValidationContext context, IEnumerable<IValidatorsFactory> factories, ISemanticLog log)
{ {
Guard.NotNull(context, nameof(context)); Guard.NotNull(context, nameof(context));
Guard.NotNull(factories, nameof(factories)); Guard.NotNull(factories, nameof(factories));
@ -40,6 +42,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
this.context = context; this.context = context;
this.factories = factories; this.factories = factories;
this.log = log;
this.partitionResolver = partitionResolver; this.partitionResolver = partitionResolver;
} }
@ -72,7 +75,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
{ {
Guard.NotNull(data, nameof(data)); Guard.NotNull(data, nameof(data));
var validator = new AggregateValidator(CreateContentValidators()); var validator = new AggregateValidator(CreateContentValidators(), log);
return validator.ValidateAsync(data, context, AddError); return validator.ValidateAsync(data, context, AddError);
} }
@ -108,7 +111,7 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
return new AggregateValidator( return new AggregateValidator(
CreateFieldValidators(field) CreateFieldValidators(field)
.Union(Enumerable.Repeat( .Union(Enumerable.Repeat(
new ObjectValidator<IJsonValue>(fieldsValidators, isPartial, typeName), 1))); new ObjectValidator<IJsonValue>(fieldsValidators, isPartial, typeName), 1)), log);
} }
private IValidator CreateFieldValidator(IField field) private IValidator CreateFieldValidator(IField field)

14
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ValidationContext.cs

@ -48,13 +48,17 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
ValidationMode mode = ValidationMode.Default) ValidationMode mode = ValidationMode.Default)
{ {
AppId = appId; AppId = appId;
ContentId = contentId; ContentId = contentId;
IsOptional = isOptional;
Mode = mode; Mode = mode;
Path = path;
Schema = schema; Schema = schema;
SchemaId = schemaId; SchemaId = schemaId;
IsOptional = isOptional;
Path = path;
} }
public ValidationContext Optimized(bool isOptimized = true) public ValidationContext Optimized(bool isOptimized = true)
@ -69,14 +73,14 @@ namespace Squidex.Domain.Apps.Core.ValidateContent
return Clone(Path, IsOptional, mode); return Clone(Path, IsOptional, mode);
} }
public ValidationContext Optional(bool isOptional) public ValidationContext Optional(bool fieldIsOptional)
{ {
if (IsOptional == isOptional) if (IsOptional == fieldIsOptional)
{ {
return this; return this;
} }
return Clone(Path, isOptional, Mode); return Clone(Path, fieldIsOptional, Mode);
} }
public ValidationContext Nested(string property) public ValidationContext Nested(string property)

25
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/AggregateValidator.cs

@ -5,29 +5,44 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Translations;
namespace Squidex.Domain.Apps.Core.ValidateContent.Validators namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{ {
public sealed class AggregateValidator : IValidator public sealed class AggregateValidator : IValidator
{ {
private readonly IValidator[]? validators; private readonly IValidator[]? validators;
private readonly ISemanticLog log;
public AggregateValidator(IEnumerable<IValidator>? validators) public AggregateValidator(IEnumerable<IValidator>? validators, ISemanticLog log)
{ {
this.validators = validators?.ToArray(); this.validators = validators?.ToArray();
this.log = log;
} }
public Task ValidateAsync(object? value, ValidationContext context, AddError addError) public async Task ValidateAsync(object? value, ValidationContext context, AddError addError)
{ {
if (validators?.Length > 0) try
{ {
return Task.WhenAll(validators.Select(x => x.ValidateAsync(value, context, addError))); if (validators?.Length > 0)
{
await Task.WhenAll(validators.Select(x => x.ValidateAsync(value, context, addError)));
}
} }
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "validateField")
.WriteProperty("status", "Failed"));
return Task.CompletedTask; addError(context.Path, T.Get("contents.validation.error"));
}
} }
} }
} }

35
backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/Validators/FieldValidator.cs

@ -17,24 +17,24 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
{ {
public sealed class FieldValidator : IValidator public sealed class FieldValidator : IValidator
{ {
private readonly IValidator[] validators; private readonly IValidator[]? validators;
private readonly IField field; private readonly IField field;
public FieldValidator(IEnumerable<IValidator> validators, IField field) public FieldValidator(IEnumerable<IValidator>? validators, IField field)
{ {
Guard.NotNull(field, nameof(field)); Guard.NotNull(field, nameof(field));
this.validators = validators.ToArray(); this.validators = validators?.ToArray();
this.field = field; this.field = field;
} }
public async Task ValidateAsync(object? value, ValidationContext context, AddError addError) public async Task ValidateAsync(object? value, ValidationContext context, AddError addError)
{ {
var typedValue = value;
try try
{ {
var typedValue = value;
if (value is IJsonValue jsonValue) if (value is IJsonValue jsonValue)
{ {
if (jsonValue.Type == JsonValueType.Null) if (jsonValue.Type == JsonValueType.Null)
@ -55,22 +55,23 @@ namespace Squidex.Domain.Apps.Core.ValidateContent.Validators
} }
} }
} }
if (validators?.Length > 0)
{
var tasks = new List<Task>();
foreach (var validator in validators)
{
tasks.Add(validator.ValidateAsync(typedValue, context, addError));
}
await Task.WhenAll(tasks);
}
} }
catch catch
{ {
addError(context.Path, T.Get("contents.validation.invalid")); addError(context.Path, T.Get("contents.validation.invalid"));
return;
}
if (validators?.Length > 0)
{
var tasks = new List<Task>();
foreach (var validator in validators)
{
tasks.Add(validator.ValidateAsync(typedValue, context, addError));
}
await Task.WhenAll(tasks);
} }
} }
} }

12
backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs

@ -18,6 +18,7 @@ using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
#pragma warning disable IDE0016 // Use 'throw' expression #pragma warning disable IDE0016 // Use 'throw' expression
@ -34,6 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
}; };
private readonly IScriptEngine scriptEngine; private readonly IScriptEngine scriptEngine;
private readonly ISemanticLog log;
private readonly IAppProvider appProvider; private readonly IAppProvider appProvider;
private readonly IEnumerable<IValidatorsFactory> factories; private readonly IEnumerable<IValidatorsFactory> factories;
private ISchemaEntity schema; private ISchemaEntity schema;
@ -41,11 +43,13 @@ namespace Squidex.Domain.Apps.Entities.Contents
private ContentCommand command; private ContentCommand command;
private ValidationContext validationContext; private ValidationContext validationContext;
public ContentOperationContext(IAppProvider appProvider, IEnumerable<IValidatorsFactory> factories, IScriptEngine scriptEngine) public ContentOperationContext(IAppProvider appProvider, IEnumerable<IValidatorsFactory> factories, IScriptEngine scriptEngine, ISemanticLog log)
{ {
this.appProvider = appProvider; this.appProvider = appProvider;
this.factories = factories; this.factories = factories;
this.scriptEngine = scriptEngine; this.scriptEngine = scriptEngine;
this.log = log;
} }
public ISchemaEntity Schema public ISchemaEntity Schema
@ -85,7 +89,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
public async Task ValidateInputAsync(NamedContentData data) public async Task ValidateInputAsync(NamedContentData data)
{ {
var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories); var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories, log);
await validator.ValidateInputAsync(data); await validator.ValidateInputAsync(data);
@ -94,7 +98,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
public async Task ValidateInputPartialAsync(NamedContentData data) public async Task ValidateInputPartialAsync(NamedContentData data)
{ {
var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories); var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories, log);
await validator.ValidateInputPartialAsync(data); await validator.ValidateInputPartialAsync(data);
@ -103,7 +107,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
public async Task ValidateContentAsync(NamedContentData data) public async Task ValidateContentAsync(NamedContentData data)
{ {
var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories); var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories, log);
await validator.ValidateContentAsync(data); await validator.ValidateContentAsync(data);

3
backend/src/Squidex.Shared/Texts.it.resx

@ -526,6 +526,9 @@
<data name="contents.validation.duplicates" xml:space="preserve"> <data name="contents.validation.duplicates" xml:space="preserve">
<value>Non può avere valori duplicati.</value> <value>Non può avere valori duplicati.</value>
</data> </data>
<data name="contents.validation.error" xml:space="preserve">
<value>Validation failed with internal error.</value>
</data>
<data name="contents.validation.exactValue" xml:space="preserve"> <data name="contents.validation.exactValue" xml:space="preserve">
<value>Deve essere esattamente {value}.</value> <value>Deve essere esattamente {value}.</value>
</data> </data>

3
backend/src/Squidex.Shared/Texts.nl.resx

@ -526,6 +526,9 @@
<data name="contents.validation.duplicates" xml:space="preserve"> <data name="contents.validation.duplicates" xml:space="preserve">
<value>Mag geen dubbele waarden bevatten.</value> <value>Mag geen dubbele waarden bevatten.</value>
</data> </data>
<data name="contents.validation.error" xml:space="preserve">
<value>Validation failed with internal error.</value>
</data>
<data name="contents.validation.exactValue" xml:space="preserve"> <data name="contents.validation.exactValue" xml:space="preserve">
<value>Moet exact {waarde} zijn.</value> <value>Moet exact {waarde} zijn.</value>
</data> </data>

3
backend/src/Squidex.Shared/Texts.resx

@ -526,6 +526,9 @@
<data name="contents.validation.duplicates" xml:space="preserve"> <data name="contents.validation.duplicates" xml:space="preserve">
<value>Must not contain duplicate values.</value> <value>Must not contain duplicate values.</value>
</data> </data>
<data name="contents.validation.error" xml:space="preserve">
<value>Validation failed with internal error.</value>
</data>
<data name="contents.validation.exactValue" xml:space="preserve"> <data name="contents.validation.exactValue" xml:space="preserve">
<value>Must be exactly {value}.</value> <value>Must be exactly {value}.</value>
</data> </data>

66
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ContentValidationTests.cs

@ -5,13 +5,17 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy;
using FluentAssertions; using FluentAssertions;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
@ -25,6 +29,68 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
private readonly List<ValidationError> errors = new List<ValidationError>(); private readonly List<ValidationError> errors = new List<ValidationError>();
private Schema schema = new Schema("my-schema"); private Schema schema = new Schema("my-schema");
[Fact]
public async Task Should_add_error_if_value_validator_throws_exception()
{
var validator = A.Fake<IValidator>();
A.CallTo(() => validator.ValidateAsync(A<object?>._, A<ValidationContext>._, A<AddError>._))
.Throws(new InvalidOperationException());
var validatorFactory = A.Fake<IValidatorsFactory>();
A.CallTo(() => validatorFactory.CreateValueValidators(A<ValidationContext>._, A<IField>._, A<FieldValidatorFactory>._))
.Returns(Enumerable.Repeat(validator, 1));
schema = schema.AddNumber(1, "my-field", Partitioning.Invariant,
new NumberFieldProperties());
var data =
new NamedContentData()
.AddField("my-field",
new ContentFieldData()
.AddValue("iv", 1000));
await data.ValidateAsync(languagesConfig.ToResolver(), errors, schema, factory: validatorFactory);
errors.Should().BeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Validation failed with internal error.", "my-field")
});
}
[Fact]
public async Task Should_add_error_if_field_validator_throws_exception()
{
var validator = A.Fake<IValidator>();
A.CallTo(() => validator.ValidateAsync(A<object?>._, A<ValidationContext>._, A<AddError>._))
.Throws(new InvalidOperationException());
var validatorFactory = A.Fake<IValidatorsFactory>();
A.CallTo(() => validatorFactory.CreateFieldValidators(A<ValidationContext>._, A<IField>._, A<FieldValidatorFactory>._))
.Returns(Enumerable.Repeat(validator, 1));
schema = schema.AddNumber(1, "my-field", Partitioning.Invariant,
new NumberFieldProperties());
var data =
new NamedContentData()
.AddField("my-field",
new ContentFieldData()
.AddValue("iv", 1000));
await data.ValidateAsync(languagesConfig.ToResolver(), errors, schema, factory: validatorFactory);
errors.Should().BeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Validation failed with internal error.", "my-field")
});
}
[Fact] [Fact]
public async Task Should_add_error_if_validating_data_with_unknown_field() public async Task Should_add_error_if_validating_data_with_unknown_field()
{ {

49
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/ValidationTestExtensions.cs

@ -9,23 +9,30 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Domain.Apps.Core.ValidateContent.Validators; using Squidex.Domain.Apps.Core.ValidateContent.Validators;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Validation; using Squidex.Infrastructure.Validation;
namespace Squidex.Domain.Apps.Core.Operations.ValidateContent namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
{ {
public delegate ValidationContext ValidationUpdater(ValidationContext context);
public static class ValidationTestExtensions public static class ValidationTestExtensions
{ {
private static readonly NamedId<Guid> AppId = NamedId.Of(Guid.NewGuid(), "my-app"); private static readonly NamedId<Guid> AppId = NamedId.Of(Guid.NewGuid(), "my-app");
private static readonly NamedId<Guid> SchemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); private static readonly NamedId<Guid> SchemaId = NamedId.Of(Guid.NewGuid(), "my-schema");
private static readonly ISemanticLog Log = A.Fake<ISemanticLog>();
private static readonly IValidatorsFactory Factory = new DefaultValidatorsFactory(); private static readonly IValidatorsFactory Factory = new DefaultValidatorsFactory();
public static Task ValidateAsync(this IValidator validator, object? value, IList<string> errors, public static Task ValidateAsync(this IValidator validator, object? value, IList<string> errors,
Schema? schema = null, ValidationMode mode = ValidationMode.Default, Func<ValidationContext, ValidationContext>? updater = null) Schema? schema = null,
ValidationMode mode = ValidationMode.Default,
ValidationUpdater? updater = null)
{ {
var context = CreateContext(schema, mode, updater); var context = CreateContext(schema, mode, updater);
@ -33,22 +40,28 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
} }
public static Task ValidateAsync(this IField field, object? value, IList<string> errors, public static Task ValidateAsync(this IField field, object? value, IList<string> errors,
Schema? schema = null, ValidationMode mode = ValidationMode.Default, Func<ValidationContext, ValidationContext>? updater = null) Schema? schema = null,
ValidationMode mode = ValidationMode.Default,
ValidationUpdater? updater = null,
IValidatorsFactory? factory = null)
{ {
var context = CreateContext(schema, mode, updater); var context = CreateContext(schema, mode, updater);
var validators = Factory.CreateValueValidators(context, field, null!); var validators = Factories(factory).SelectMany(x => x.CreateValueValidators(context, field, null!)).ToArray();
return new FieldValidator(validators.ToArray(), field) return new FieldValidator(validators, field)
.ValidateAsync(value, context, CreateFormatter(errors)); .ValidateAsync(value, context, CreateFormatter(errors));
} }
public static async Task ValidatePartialAsync(this NamedContentData data, PartitionResolver partitionResolver, IList<ValidationError> errors, public static async Task ValidatePartialAsync(this NamedContentData data, PartitionResolver partitionResolver, IList<ValidationError> errors,
Schema? schema = null, ValidationMode mode = ValidationMode.Default, Func<ValidationContext, ValidationContext>? updater = null) Schema? schema = null,
ValidationMode mode = ValidationMode.Default,
ValidationUpdater? updater = null,
IValidatorsFactory? factory = null)
{ {
var context = CreateContext(schema, mode, updater); var context = CreateContext(schema, mode, updater);
var validator = new ContentValidator(partitionResolver, context, Enumerable.Repeat(Factory, 1)); var validator = new ContentValidator(partitionResolver, context, Factories(factory), Log);
await validator.ValidateInputPartialAsync(data); await validator.ValidateInputPartialAsync(data);
@ -59,11 +72,14 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
} }
public static async Task ValidateAsync(this NamedContentData data, PartitionResolver partitionResolver, IList<ValidationError> errors, public static async Task ValidateAsync(this NamedContentData data, PartitionResolver partitionResolver, IList<ValidationError> errors,
Schema? schema = null, ValidationMode mode = ValidationMode.Default, Func<ValidationContext, ValidationContext>? updater = null) Schema? schema = null,
ValidationMode mode = ValidationMode.Default,
ValidationUpdater? updater = null,
IValidatorsFactory? factory = null)
{ {
var context = CreateContext(schema, mode, updater); var context = CreateContext(schema, mode, updater);
var validator = new ContentValidator(partitionResolver, context, Enumerable.Repeat(Factory, 1)); var validator = new ContentValidator(partitionResolver, context, Factories(factory), Log);
await validator.ValidateInputAsync(data); await validator.ValidateInputAsync(data);
@ -88,7 +104,22 @@ namespace Squidex.Domain.Apps.Core.Operations.ValidateContent
}; };
} }
public static ValidationContext CreateContext(Schema? schema = null, ValidationMode mode = ValidationMode.Default, Func<ValidationContext, ValidationContext>? updater = null) private static IEnumerable<IValidatorsFactory> Factories(IValidatorsFactory? factory)
{
var result = Enumerable.Repeat(Factory, 1);
if (factory != null)
{
result = result.Union(Enumerable.Repeat(factory, 1));
}
return result;
}
public static ValidationContext CreateContext(
Schema? schema = null,
ValidationMode mode = ValidationMode.Default,
ValidationUpdater? updater = null)
{ {
var context = new ValidationContext( var context = new ValidationContext(
AppId, AppId,

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs

@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
patched = patch.MergeInto(data); patched = patch.MergeInto(data);
var context = new ContentOperationContext(appProvider, Enumerable.Repeat(new DefaultValidatorsFactory(), 1), scriptEngine); var context = new ContentOperationContext(appProvider, Enumerable.Repeat(new DefaultValidatorsFactory(), 1), scriptEngine, A.Fake<ISemanticLog>());
sut = new ContentDomainObject(Store, contentWorkflow, context, A.Dummy<ISemanticLog>()); sut = new ContentDomainObject(Store, contentWorkflow, context, A.Dummy<ISemanticLog>());
sut.Setup(Id); sut.Setup(Id);

Loading…
Cancel
Save