Provide custom required validator for block list and toggle (#18474)
* Provide custom required validator for block list. * Adds a custom required validator for the toggle to ensure the value provided is true. * Remove unnecessary usings * Remove redundant interface and base constructor * Remove unnecessary interface --------- Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
@@ -88,7 +88,7 @@ public class PropertyValidationService : IPropertyValidationService
|
||||
{
|
||||
// Retrieve default messages used for required and regex validatation. We'll replace these
|
||||
// if set with custom ones if they've been provided for a given property.
|
||||
var requiredDefaultMessages = new[] { Constants.Validation.ErrorMessages.Properties.Missing };
|
||||
var requiredDefaultMessages = new[] { Constants.Validation.ErrorMessages.Properties.Missing, Constants.Validation.ErrorMessages.Properties.Empty };
|
||||
var formatDefaultMessages = new[] { Constants.Validation.ErrorMessages.Properties.PatternMismatch };
|
||||
|
||||
IDataValueEditor valueEditor = _valueEditorCache.GetValueEditor(editor, dataType);
|
||||
|
||||
@@ -20,8 +20,6 @@ public abstract class BlockEditorPropertyValueEditor<TValue, TLayout> : BlockVal
|
||||
where TValue : BlockValue<TLayout>, new()
|
||||
where TLayout : class, IBlockLayoutItem, new()
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
[Obsolete("Please use the non-obsolete constructor. Will be removed in V16.")]
|
||||
protected BlockEditorPropertyValueEditor(
|
||||
DataEditorAttribute attribute,
|
||||
@@ -52,7 +50,12 @@ public abstract class BlockEditorPropertyValueEditor<TValue, TLayout> : BlockVal
|
||||
IIOHelper ioHelper,
|
||||
DataEditorAttribute attribute)
|
||||
: base(propertyEditors, dataTypeConfigurationCache, shortStringHelper, jsonSerializer, dataValueReferenceFactories, blockEditorVarianceHandler, languageService, ioHelper, attribute) =>
|
||||
_jsonSerializer = jsonSerializer;
|
||||
JsonSerializer = jsonSerializer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IJsonSerializer"/>.
|
||||
/// </summary>
|
||||
protected IJsonSerializer JsonSerializer { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<UmbracoEntityReference> GetReferences(object? value)
|
||||
@@ -143,6 +146,6 @@ public abstract class BlockEditorPropertyValueEditor<TValue, TLayout> : BlockVal
|
||||
MapBlockValueFromEditor(blockEditorData.BlockValue);
|
||||
|
||||
// return json
|
||||
return _jsonSerializer.Serialize(blockEditorData.BlockValue);
|
||||
return JsonSerializer.Serialize(blockEditorData.BlockValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.PropertyEditors.Validators;
|
||||
using StaticServiceProvider = Umbraco.Cms.Core.DependencyInjection.StaticServiceProvider;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
@@ -74,6 +75,9 @@ public abstract class BlockListPropertyEditorBase : DataEditor
|
||||
Validators.Add(new MinMaxValidator(BlockEditorValues, textService));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IValueRequiredValidator RequiredValidator => new BlockListValueRequiredValidator(JsonSerializer);
|
||||
|
||||
protected override BlockListValue CreateWithLayout(IEnumerable<BlockListLayoutItem> layout) => new(layout);
|
||||
|
||||
private class MinMaxValidator : BlockEditorMinMaxValidatorBase<BlockListValue, BlockListLayoutItem>
|
||||
|
||||
@@ -10,7 +10,6 @@ using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
|
||||
@@ -6,11 +6,12 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Editors;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.PropertyEditors.Validators;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a checkbox property and parameter editor.
|
||||
/// Represents a true/false (toggle) property editor.
|
||||
/// </summary>
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Boolean,
|
||||
@@ -29,8 +30,14 @@ public class TrueFalsePropertyEditor : DataEditor
|
||||
protected override IDataValueEditor CreateValueEditor()
|
||||
=> DataValueEditorFactory.Create<TrueFalsePropertyValueEditor>(Attribute!);
|
||||
|
||||
/// <summary>
|
||||
/// Defines the value editor for the true/false (toggle) property editor.
|
||||
/// </summary>
|
||||
internal class TrueFalsePropertyValueEditor : DataValueEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TrueFalsePropertyValueEditor"/> class.
|
||||
/// </summary>
|
||||
public TrueFalsePropertyValueEditor(
|
||||
IShortStringHelper shortStringHelper,
|
||||
IJsonSerializer jsonSerializer,
|
||||
@@ -40,10 +47,17 @@ public class TrueFalsePropertyEditor : DataEditor
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IValueRequiredValidator RequiredValidator => new TrueFalseValueRequiredValidator();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override object? ToEditor(IProperty property, string? culture = null, string? segment = null)
|
||||
=> ParsePropertyValue(property.GetValue(culture, segment));
|
||||
|
||||
// NOTE: property editor value type is Integer, which means we need to store the boolean representation as 0 or 1
|
||||
/// <inheritdoc/>
|
||||
/// <remarks>
|
||||
/// NOTE: property editor value type is Integer, which means we need to store the boolean representation as 0 or 1.
|
||||
/// </remarks>
|
||||
public override object? FromEditor(ContentPropertyData editorValue, object? currentValue)
|
||||
=> ParsePropertyValue(editorValue.Value) ? 1 : 0;
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Cms.Core.PropertyEditors.Validators;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PropertyEditors.Validators;
|
||||
|
||||
/// <summary>
|
||||
/// Custom validator for block value required validation.
|
||||
/// </summary>
|
||||
internal class BlockListValueRequiredValidator : RequiredValidator
|
||||
{
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BlockListValueRequiredValidator"/> class.
|
||||
/// </summary>
|
||||
public BlockListValueRequiredValidator(IJsonSerializer jsonSerializer) => _jsonSerializer = jsonSerializer;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerable<ValidationResult> ValidateRequired(object? value, string? valueType)
|
||||
{
|
||||
IEnumerable<ValidationResult> validationResults = base.ValidateRequired(value, valueType);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
return validationResults;
|
||||
}
|
||||
|
||||
if (_jsonSerializer.TryDeserialize(value, out BlockListValue? blockListValue) &&
|
||||
blockListValue.ContentData.Count == 0 &&
|
||||
blockListValue.Layout.Count == 0)
|
||||
{
|
||||
validationResults = validationResults.Append(new ValidationResult(Constants.Validation.ErrorMessages.Properties.Empty, ["value"]));
|
||||
}
|
||||
|
||||
return validationResults;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.PropertyEditors.Validators;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PropertyEditors.Validators;
|
||||
|
||||
/// <summary>
|
||||
/// Custom validator for true/false (toggle) required validation.
|
||||
/// </summary>
|
||||
internal class TrueFalseValueRequiredValidator : RequiredValidator
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override IEnumerable<ValidationResult> ValidateRequired(object? value, string? valueType)
|
||||
{
|
||||
IEnumerable<ValidationResult> validationResults = base.ValidateRequired(value, valueType);
|
||||
|
||||
if (value is null)
|
||||
{
|
||||
return validationResults;
|
||||
}
|
||||
|
||||
if (value is bool valueAsBool && valueAsBool is false)
|
||||
{
|
||||
validationResults = validationResults.Append(new ValidationResult(Constants.Validation.ErrorMessages.Properties.Empty, ["value"]));
|
||||
}
|
||||
|
||||
return validationResults;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Text.Json.Nodes;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models.Blocks;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Infrastructure.PropertyEditors.Validators;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
public class BlockListValueRequiredValidatorTests
|
||||
{
|
||||
[Test]
|
||||
public void Validates_Empty_Block_List_As_Not_Provided()
|
||||
{
|
||||
var validator = new BlockListValueRequiredValidator(new SystemTextJsonSerializer());
|
||||
|
||||
var value = JsonNode.Parse("{ \"contentData\": [], \"settingsData\": [] }");
|
||||
var result = validator.ValidateRequired(value, ValueTypes.Json);
|
||||
Assert.AreEqual(1, result.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Validates_Populated_Block_List_As_Provided()
|
||||
{
|
||||
var validator = new BlockListValueRequiredValidator(new SystemTextJsonSerializer());
|
||||
|
||||
var value = JsonNode.Parse("{ \"contentData\": [ {} ], \"settingsData\": [] }");
|
||||
var result = validator.ValidateRequired(value, ValueTypes.Json);
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Infrastructure.PropertyEditors.Validators;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
|
||||
|
||||
[TestFixture]
|
||||
public class TrueFalseValueRequiredValidatorTests
|
||||
{
|
||||
[Test]
|
||||
public void Validates_Null_Value_As_Not_Provided()
|
||||
{
|
||||
var validator = new TrueFalseValueRequiredValidator();
|
||||
|
||||
var result = validator.ValidateRequired(null, ValueTypes.Integer);
|
||||
Assert.AreEqual(1, result.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Validates_False_Value_As_Not_Provided()
|
||||
{
|
||||
var validator = new TrueFalseValueRequiredValidator();
|
||||
|
||||
var result = validator.ValidateRequired(false, ValueTypes.Integer);
|
||||
Assert.AreEqual(1, result.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Validates_True_Value_As_Provided()
|
||||
{
|
||||
var validator = new TrueFalseValueRequiredValidator();
|
||||
|
||||
var result = validator.ValidateRequired(true, ValueTypes.Integer);
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user