mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
4.1 KiB
109 lines
4.1 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Squidex.Domain.Apps.Core;
|
|
using Squidex.Domain.Apps.Core.Contents;
|
|
using Squidex.Domain.Apps.Core.Schemas;
|
|
using Squidex.Domain.Apps.Core.ValidateContent;
|
|
using Squidex.Domain.Apps.Entities.Contents.Repositories;
|
|
using Squidex.Infrastructure.Json.Objects;
|
|
using Squidex.Infrastructure.Queries;
|
|
|
|
namespace Squidex.Extensions.Validation
|
|
{
|
|
internal sealed class CompositeUniqueValidator : IValidator
|
|
{
|
|
private readonly string tag;
|
|
private readonly IContentRepository contentRepository;
|
|
|
|
public CompositeUniqueValidator(string tag, IContentRepository contentRepository)
|
|
{
|
|
this.tag = tag;
|
|
|
|
this.contentRepository = contentRepository;
|
|
}
|
|
|
|
public async Task ValidateAsync(object value, ValidationContext context, AddError addError)
|
|
{
|
|
if (value is NamedContentData data)
|
|
{
|
|
var validateableFields = context.Schema.Fields.Where(IsValidateableField);
|
|
|
|
var filters = new List<FilterNode<ClrValue>>();
|
|
|
|
foreach (var field in validateableFields)
|
|
{
|
|
var fieldValue = TryGetValue(field, data);
|
|
|
|
if (fieldValue != null)
|
|
{
|
|
filters.Add(ClrFilter.Eq($"data.{field.Name}.iv", fieldValue));
|
|
}
|
|
}
|
|
|
|
if (filters.Count > 0)
|
|
{
|
|
var filter = ClrFilter.And(filters);
|
|
|
|
var found = await contentRepository.QueryIdsAsync(context.AppId.Id, context.SchemaId.Id, filter);
|
|
|
|
if (found.Any(x => x.Id != context.ContentId))
|
|
{
|
|
addError(Enumerable.Empty<string>(), "A content with the same values already exist.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static ClrValue TryGetValue(IRootField field, NamedContentData data)
|
|
{
|
|
var value = JsonValue.Null;
|
|
|
|
if (data.TryGetValue(field.Name, out var fieldValue))
|
|
{
|
|
if (fieldValue.TryGetValue(InvariantPartitioning.Key, out var temp) && temp != null)
|
|
{
|
|
value = temp;
|
|
}
|
|
}
|
|
|
|
switch (field.RawProperties)
|
|
{
|
|
case BooleanFieldProperties _ when value is JsonBoolean boolean:
|
|
return boolean.Value;
|
|
case BooleanFieldProperties _ when value is JsonNull:
|
|
return ClrValue.Null;
|
|
case NumberFieldProperties _ when value is JsonNumber number:
|
|
return number.Value;
|
|
case NumberFieldProperties _ when value is JsonNull:
|
|
return ClrValue.Null;
|
|
case StringFieldProperties _ when value is JsonString @string:
|
|
return @string.Value;
|
|
case StringFieldProperties _ when value is JsonNull:
|
|
return ClrValue.Null;
|
|
case ReferencesFieldProperties _ when value is JsonArray array && array.FirstOrDefault() is JsonString @string:
|
|
return @string.Value;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private bool IsValidateableField(IRootField field)
|
|
{
|
|
return
|
|
field.Partitioning == Partitioning.Invariant &&
|
|
field.RawProperties.Tags?.Contains(tag) == true &&
|
|
(field.RawProperties is BooleanFieldProperties ||
|
|
field.RawProperties is NumberFieldProperties ||
|
|
field.RawProperties is ReferencesFieldProperties ||
|
|
field.RawProperties is StringFieldProperties);
|
|
}
|
|
}
|
|
}
|
|
|