V15: Add textbox and text area serverside validation (#18596)
* Add validation to TextOnlyValueEditor * Fix tests * Add tests
This commit is contained in:
@@ -125,6 +125,7 @@ Mange hilsner fra Umbraco robotten
|
||||
<key alias="outOfRangeMultipleItemsMaximum">De %0% enheder givet er større end det tilladte minimum af %1%.</key>
|
||||
<key alias="invalidStep">Værdien %0% passer ikke med den konfigureret trin værdi af %1% og mindste værdi af %2%.</key>
|
||||
<key alias="unexpectedRange">Værdien %0% forventes ikke at indeholde et spænd.</key>
|
||||
<key alias="stringLengthExceeded">Tekststrengen er længere end den tilladte længde på %0% tegn.</key>
|
||||
<key alias="invalidRange">Værdien %0% forventes at have en værdi der er større end fra værdien.</key>
|
||||
<key alias="invalidObjectType">Det valgte indhold er af den forkerte type.</key>
|
||||
<key alias="notOneOfOptions">"Værdien '%0%' er ikke en af de tilgængelige valgmuligheder.</key>
|
||||
|
||||
@@ -378,6 +378,7 @@
|
||||
<key alias="invalidPattern">Value is invalid, it does not match the correct pattern</key>
|
||||
<key alias="entriesShort"><![CDATA[Minimum %0% entries, requires <strong>%1%</strong> more.]]></key>
|
||||
<key alias="entriesExceed"><![CDATA[Maximum %0% entries, <strong>%1%</strong> too many.]]></key>
|
||||
<key alias="stringLengthExceeded">The string length exceeds the maximum length of %0% characters.</key>
|
||||
<key alias="entriesAreasMismatch">The content amount requirements are not met for one or more areas.</key>
|
||||
<key alias="invalidMemberGroupName">Invalid member group name</key>
|
||||
<key alias="invalidUserGroupName">Invalid user group name</key>
|
||||
|
||||
@@ -395,6 +395,7 @@
|
||||
<key alias="invalidRange">The value %0% is not expected to have a to value less than the from value</key>
|
||||
<key alias="entriesShort"><![CDATA[Minimum %0% entries, requires <strong>%1%</strong> more.]]></key>
|
||||
<key alias="entriesExceed"><![CDATA[Maximum %0% entries, <strong>%1%</strong> too many.]]></key>
|
||||
<key alias="stringLengthExceeded">The string length exceeds the maximum length of %0% characters.</key>
|
||||
<key alias="entriesAreasMismatch">The content amount requirements are not met for one or more areas.</key>
|
||||
<key alias="invalidMediaType">The chosen media type is invalid.</key>
|
||||
<key alias="invalidContentType">The chosen content is of invalid type.</key>
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Validation;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
@@ -12,23 +17,27 @@ namespace Umbraco.Cms.Core.PropertyEditors;
|
||||
/// </summary>
|
||||
public class TextOnlyValueEditor : DataValueEditor
|
||||
{
|
||||
[Obsolete($"Use the constructor that does not accept {nameof(ILocalizedTextService)}. Will be removed in V15.")]
|
||||
public TextOnlyValueEditor(
|
||||
DataEditorAttribute attribute,
|
||||
ILocalizedTextService localizedTextService,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IIOHelper ioHelper)
|
||||
: this(attribute, shortStringHelper, jsonSerializer, ioHelper)
|
||||
{
|
||||
}
|
||||
: base(shortStringHelper, jsonSerializer, ioHelper, attribute) =>
|
||||
Validators.Add(new LengthValidator(localizedTextService));
|
||||
|
||||
[Obsolete($"Use the constructor that accepts {nameof(ILocalizedTextService)}. Will be removed in V16.")]
|
||||
public TextOnlyValueEditor(
|
||||
DataEditorAttribute attribute,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IIOHelper ioHelper)
|
||||
: base(shortStringHelper, jsonSerializer, ioHelper, attribute)
|
||||
: this(
|
||||
attribute,
|
||||
StaticServiceProvider.Instance.GetRequiredService<ILocalizedTextService>(),
|
||||
shortStringHelper,
|
||||
jsonSerializer,
|
||||
ioHelper)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -65,4 +74,48 @@ public class TextOnlyValueEditor : DataValueEditor
|
||||
" can only be used with string based property editors");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A common length validator for both textbox and text area.
|
||||
/// </summary>
|
||||
internal class LengthValidator : IValueValidator
|
||||
{
|
||||
private readonly ILocalizedTextService _localizedTextService;
|
||||
|
||||
public LengthValidator(ILocalizedTextService localizedTextService)
|
||||
{
|
||||
_localizedTextService = localizedTextService;
|
||||
}
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(object? value, string? valueType, object? dataTypeConfiguration,
|
||||
PropertyValidationContext validationContext)
|
||||
{
|
||||
int? maxCharacters = dataTypeConfiguration switch
|
||||
{
|
||||
TextAreaConfiguration areaConfiguration => areaConfiguration.MaxChars,
|
||||
TextboxConfiguration textboxConfiguration => textboxConfiguration.MaxChars,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (maxCharacters is null)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if (value is string typedValue && typedValue.Length > maxCharacters)
|
||||
{
|
||||
return
|
||||
[
|
||||
new ValidationResult(
|
||||
_localizedTextService.Localize(
|
||||
"validation",
|
||||
"stringLengthExceeded",
|
||||
[maxCharacters.ToString()]),
|
||||
["value'"])
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,6 +632,7 @@ public class VariationTests
|
||||
var dataValueEditorFactory = Mock.Of<IDataValueEditorFactory>(x
|
||||
=> x.Create<TextOnlyValueEditor>(It.IsAny<DataEditorAttribute>()) == new TextOnlyValueEditor(
|
||||
attribute,
|
||||
Mock.Of<ILocalizedTextService>(),
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
new SystemTextJsonSerializer(),
|
||||
Mock.Of<IIOHelper>()));
|
||||
|
||||
@@ -29,6 +29,7 @@ public class DataValueEditorReuseTests
|
||||
.Setup(m => m.Create<TextOnlyValueEditor>(It.IsAny<DataEditorAttribute>()))
|
||||
.Returns(() => new TextOnlyValueEditor(
|
||||
new DataEditorAttribute("a"),
|
||||
Mock.Of<ILocalizedTextService>(),
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
Mock.Of<IJsonSerializer>(),
|
||||
Mock.Of<IIOHelper>()));
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models.Validation;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Serialization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors.Validators;
|
||||
|
||||
[TestFixture]
|
||||
internal class TextOnlyValueEditorValidatorTests
|
||||
{
|
||||
internal enum ConfigurationType
|
||||
{
|
||||
TextAreaConfiguration,
|
||||
TextboxConfiguration,
|
||||
}
|
||||
|
||||
[TestCase(true, ConfigurationType.TextboxConfiguration, null, "123")]
|
||||
[TestCase(true, ConfigurationType.TextAreaConfiguration, null, "123")]
|
||||
[TestCase(false, ConfigurationType.TextAreaConfiguration, 2, "123")]
|
||||
[TestCase(false, ConfigurationType.TextboxConfiguration, 2, "123")]
|
||||
[TestCase(true, ConfigurationType.TextboxConfiguration, 10, "123")]
|
||||
[TestCase(true, ConfigurationType.TextAreaConfiguration, 10, "123")]
|
||||
public void Validates_String_Length(bool shouldSucceed, ConfigurationType configurationType, int? maxChars, string value)
|
||||
{
|
||||
var editor = CreateValueEditor();
|
||||
|
||||
editor.ConfigurationObject = CreateConfiguration(configurationType, maxChars);
|
||||
|
||||
var results = editor.Validate(value, false, null, PropertyValidationContext.Empty());
|
||||
|
||||
ValidateResult(shouldSucceed, results);
|
||||
}
|
||||
|
||||
private static object CreateConfiguration(ConfigurationType type, int? maxChars) =>
|
||||
type switch
|
||||
{
|
||||
ConfigurationType.TextboxConfiguration => new TextboxConfiguration { MaxChars = maxChars },
|
||||
ConfigurationType.TextAreaConfiguration => new TextAreaConfiguration { MaxChars = maxChars },
|
||||
_ => throw new InvalidOperationException(),
|
||||
};
|
||||
|
||||
private static void ValidateResult(bool succeed, IEnumerable<ValidationResult> result)
|
||||
{
|
||||
if (succeed)
|
||||
{
|
||||
Assert.IsEmpty(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNotEmpty(result);
|
||||
}
|
||||
}
|
||||
|
||||
private TextOnlyValueEditor CreateValueEditor() =>
|
||||
new(
|
||||
new DataEditorAttribute("alias"),
|
||||
Mock.Of<ILocalizedTextService>(),
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
new SystemTextJsonSerializer(),
|
||||
Mock.Of<IIOHelper>());
|
||||
}
|
||||
@@ -279,7 +279,7 @@ public class PropertyValidationServiceTests
|
||||
IShortStringHelper shortStringHelper,
|
||||
IJsonSerializer jsonSerializer,
|
||||
IIOHelper ioHelper)
|
||||
: base(attribute, shortStringHelper, jsonSerializer, ioHelper)
|
||||
: base(attribute, Mock.Of<ILocalizedTextService>(), shortStringHelper, jsonSerializer, ioHelper)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user