From a90f0c407027e7a93aa3923cdbfc45fbad368c5a Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Wed, 26 Jun 2019 14:37:02 +0200 Subject: [PATCH 01/15] Added custom validation messages to property types: model, dto and migration, update via property type editing, display when content editing. --- .../Migrations/Upgrade/UmbracoPlan.cs | 1 + ...AddPropertyTypeValidationMessageColumns.cs | 20 +++++++ src/Umbraco.Core/Models/PropertyType.cs | 24 ++++++++- .../Packaging/PackageDataInstallation.cs | 2 + .../Persistence/Dtos/PropertyTypeDto.cs | 10 ++++ .../Dtos/PropertyTypeReadOnlyDto.cs | 6 +++ .../Factories/PropertyGroupFactory.cs | 4 ++ .../Persistence/Mappers/PropertyTypeMapper.cs | 2 + .../Implement/ContentTypeCommonRepository.cs | 2 + .../PropertyEditors/DataValueEditor.cs | 6 +-- .../PropertyEditors/IDataValueEditor.cs | 6 ++- .../PropertyEditors/IValueFormatValidator.cs | 5 +- .../IValueRequiredValidator.cs | 5 +- .../Validators/RegexValidator.cs | 19 +++++-- .../Validators/RequiredValidator.cs | 22 ++++++-- .../Services/Implement/EntityXmlSerializer.cs | 4 ++ .../Services/PropertyValidationService.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Mapping/ContentTypeModelMappingTests.cs | 32 ++++++----- .../components/umbgroupsbuilder.directive.js | 6 ++- .../less/components/umb-group-builder.less | 16 ++++-- src/Umbraco.Web.UI.Client/src/less/forms.less | 3 +- .../propertysettings/propertysettings.html | 53 ++++++++++++------- .../textbox/textbox.controller.js | 11 +++- .../propertyeditors/textbox/textbox.html | 4 +- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 2 + .../Umbraco/config/lang/en_us.xml | 2 + .../Editors/Filters/ContentModelValidator.cs | 2 +- .../ContentEditing/ContentPropertyDto.cs | 7 +++ .../ContentEditing/PropertyTypeValidation.cs | 6 +++ .../Mapping/ContentPropertyDisplayMapper.cs | 2 + .../Mapping/ContentPropertyDtoMapper.cs | 2 + .../Mapping/ContentTypeMapDefinition.cs | 2 + .../Models/Mapping/PropertyTypeGroupMapper.cs | 8 ++- .../NestedContentPropertyEditor.cs | 19 +++++-- .../PropertyEditors/TagsPropertyEditor.cs | 2 +- 36 files changed, 254 insertions(+), 66 deletions(-) create mode 100644 src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/AddPropertyTypeValidationMessageColumns.cs diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index 834eade986..3a3c9cffc5 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -176,6 +176,7 @@ namespace Umbraco.Core.Migrations.Upgrade To("{B69B6E8C-A769-4044-A27E-4A4E18D1645A}"); To("{0372A42B-DECF-498D-B4D1-6379E907EB94}"); To("{5B1E0D93-F5A3-449B-84BA-65366B84E2D4}"); + To("{3D67D2C8-5E65-47D0-A9E1-DC2EE0779D6B}"); //FINAL } diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/AddPropertyTypeValidationMessageColumns.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/AddPropertyTypeValidationMessageColumns.cs new file mode 100644 index 0000000000..07514faf75 --- /dev/null +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/AddPropertyTypeValidationMessageColumns.cs @@ -0,0 +1,20 @@ +using System.Linq; +using Umbraco.Core.Persistence.Dtos; + +namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0 +{ + public class AddPropertyTypeValidationMessageColumns : MigrationBase + { + public AddPropertyTypeValidationMessageColumns(IMigrationContext context) + : base(context) + { } + + public override void Migrate() + { + var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList(); + + AddColumnIfNotExists(columns, "mandatoryMessage"); + AddColumnIfNotExists(columns, "validationRegExpMessage"); + } + } +} diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 1e950a876c..1ae5133f8d 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -25,8 +25,10 @@ namespace Umbraco.Core.Models private string _propertyEditorAlias; private ValueStorageType _valueStorageType; private bool _mandatory; + private string _mandatoryMessage; private int _sortOrder; private string _validationRegExp; + private string _validationRegExpMessage; private ContentVariation _variations; /// @@ -175,7 +177,7 @@ namespace Umbraco.Core.Models } /// - /// Gets of sets a value indicating whether a value for this property type is required. + /// Gets or sets a value indicating whether a value for this property type is required. /// [DataMember] public bool Mandatory @@ -184,6 +186,16 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _mandatory, nameof(Mandatory)); } + /// + /// Gets or sets the custom validation message used when a value for this PropertyType is required + /// + [DataMember] + public string MandatoryMessage + { + get => _mandatoryMessage; + set => SetPropertyValueAndDetectChanges(value, ref _mandatoryMessage, nameof(MandatoryMessage)); + } + /// /// Gets of sets the sort order of the property type. /// @@ -204,6 +216,16 @@ namespace Umbraco.Core.Models set => SetPropertyValueAndDetectChanges(value, ref _validationRegExp, nameof(ValidationRegExp)); } + /// + /// Gets or sets the custom validation message used when a pattern for this PropertyType must be matched + /// + [DataMember] + public string ValidationRegExpMessage + { + get => _validationRegExpMessage; + set => SetPropertyValueAndDetectChanges(value, ref _validationRegExpMessage, nameof(ValidationRegExpMessage)); + } + /// /// Gets or sets the content variation of the property type. /// diff --git a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs index c811f484bc..d5738b5e3f 100644 --- a/src/Umbraco.Core/Packaging/PackageDataInstallation.cs +++ b/src/Umbraco.Core/Packaging/PackageDataInstallation.cs @@ -749,7 +749,9 @@ namespace Umbraco.Core.Packaging Name = property.Element("Name").Value, Description = (string)property.Element("Description"), Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false, + MandatoryMessage = property.Element("MandatoryMessage") != null ? (string)property.Element("MandatoryMessage") : string.Empty, ValidationRegExp = (string)property.Element("Validation"), + ValidationRegExpMessage = property.Element("ValidationRegExpMessage") != null ? (string)property.Element("ValidationRegExpMessage") : string.Empty, SortOrder = sortOrder }; diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs index 8c52aa1e15..3e8d6e7496 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeDto.cs @@ -43,10 +43,20 @@ namespace Umbraco.Core.Persistence.Dtos [Constraint(Default = "0")] public bool Mandatory { get; set; } + [Column("mandatoryMessage")] + [NullSetting(NullSetting = NullSettings.Null)] + [Length(500)] + public string MandatoryMessage { get; set; } + [Column("validationRegExp")] [NullSetting(NullSetting = NullSettings.Null)] public string ValidationRegExp { get; set; } + [Column("validationRegExpMessage")] + [NullSetting(NullSetting = NullSettings.Null)] + [Length(500)] + public string ValidationRegExpMessage { get; set; } + [Column("Description")] [NullSetting(NullSetting = NullSettings.Null)] [Length(2000)] diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs index c68dee42b5..4c352a0134 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/PropertyTypeReadOnlyDto.cs @@ -32,9 +32,15 @@ namespace Umbraco.Core.Persistence.Dtos [Column("mandatory")] public bool Mandatory { get; set; } + [Column("mandatoryMessage")] + public string MandatoryMessage { get; set; } + [Column("validationRegExp")] public string ValidationRegExp { get; set; } + [Column("validationRegExpMessage")] + public string ValidationRegExpMessage { get; set; } + [Column("Description")] public string Description { get; set; } diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs index c134748047..0846d6d1f6 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs @@ -59,8 +59,10 @@ namespace Umbraco.Core.Persistence.Factories propertyType.Key = typeDto.UniqueId; propertyType.Name = typeDto.Name; propertyType.Mandatory = typeDto.Mandatory; + propertyType.MandatoryMessage = typeDto.MandatoryMessage; propertyType.SortOrder = typeDto.SortOrder; propertyType.ValidationRegExp = typeDto.ValidationRegExp; + propertyType.ValidationRegExpMessage = typeDto.ValidationRegExpMessage; propertyType.PropertyGroupId = new Lazy(() => tempGroupDto.Id); propertyType.CreateDate = createDate; propertyType.UpdateDate = updateDate; @@ -123,9 +125,11 @@ namespace Umbraco.Core.Persistence.Factories DataTypeId = propertyType.DataTypeId, Description = propertyType.Description, Mandatory = propertyType.Mandatory, + MandatoryMessage = propertyType.MandatoryMessage, Name = propertyType.Name, SortOrder = propertyType.SortOrder, ValidationRegExp = propertyType.ValidationRegExp, + ValidationRegExpMessage = propertyType.ValidationRegExpMessage, UniqueId = propertyType.Key, Variations = (byte)propertyType.Variations }; diff --git a/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs index ab1869a7f5..6f22b61f9a 100644 --- a/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/PropertyTypeMapper.cs @@ -24,9 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers DefineMap(nameof(PropertyType.DataTypeId), nameof(PropertyTypeDto.DataTypeId)); DefineMap(nameof(PropertyType.Description), nameof(PropertyTypeDto.Description)); DefineMap(nameof(PropertyType.Mandatory), nameof(PropertyTypeDto.Mandatory)); + DefineMap(nameof(PropertyType.MandatoryMessage), nameof(PropertyTypeDto.MandatoryMessage)); DefineMap(nameof(PropertyType.Name), nameof(PropertyTypeDto.Name)); DefineMap(nameof(PropertyType.SortOrder), nameof(PropertyTypeDto.SortOrder)); DefineMap(nameof(PropertyType.ValidationRegExp), nameof(PropertyTypeDto.ValidationRegExp)); + DefineMap(nameof(PropertyType.ValidationRegExpMessage), nameof(PropertyTypeDto.ValidationRegExpMessage)); DefineMap(nameof(PropertyType.PropertyEditorAlias), nameof(DataTypeDto.EditorAlias)); DefineMap(nameof(PropertyType.ValueStorageType), nameof(DataTypeDto.DbType)); } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs index ccafb9f771..8cbcf4a523 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs @@ -293,10 +293,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement Id = dto.Id, Key = dto.UniqueId, Mandatory = dto.Mandatory, + MandatoryMessage = dto.MandatoryMessage, Name = dto.Name, PropertyGroupId = groupId.HasValue ? new Lazy(() => groupId.Value) : null, SortOrder = dto.SortOrder, ValidationRegExp = dto.ValidationRegExp, + ValidationRegExpMessage = dto.ValidationRegExpMessage, Variations = (ContentVariation)dto.Variations }; } diff --git a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs index c4380f032c..b88c49583f 100644 --- a/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueEditor.cs @@ -85,7 +85,7 @@ namespace Umbraco.Core.PropertyEditors public string ValueType { get; set; } /// - public IEnumerable Validate(object value, bool required, string format) + public IEnumerable Validate(object value, bool required, string requiredMessage, string format, string formatMessage) { List results = null; var r = Validators.SelectMany(v => v.Validate(value, ValueType, Configuration)).ToList(); @@ -97,14 +97,14 @@ namespace Umbraco.Core.PropertyEditors if (required) { - r = RequiredValidator.ValidateRequired(value, ValueType).ToList(); + r = RequiredValidator.ValidateRequired(value, ValueType, requiredMessage).ToList(); if (r.Any()) { if (results == null) results = r; else results.AddRange(r); } } var stringValue = value?.ToString(); if (!string.IsNullOrWhiteSpace(format) && !string.IsNullOrWhiteSpace(stringValue)) { - r = FormatValidator.ValidateFormat(value, ValueType, format).ToList(); + r = FormatValidator.ValidateFormat(value, ValueType, format, formatMessage).ToList(); if (r.Any()) { if (results == null) results = r; else results.AddRange(r); } } diff --git a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs index cb68531cc7..0db4881da4 100644 --- a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs @@ -35,12 +35,14 @@ namespace Umbraco.Core.PropertyEditors bool HideLabel { get; } /// - /// Validates a property value. + /// Validates a property value using custom messages. /// /// The property value. /// A value indicating whether the property value is required. + /// A custom validation message to use when the property value is required. /// A specific format (regex) that the property value must respect. - IEnumerable Validate(object value, bool required, string format); + /// A custom validation message to use when the property value is does not match the specific format (regex). + IEnumerable Validate(object value, bool required, string requiredMessage, string format, string formatMessage); /// /// Gets the validators to use to validate the edited value. diff --git a/src/Umbraco.Core/PropertyEditors/IValueFormatValidator.cs b/src/Umbraco.Core/PropertyEditors/IValueFormatValidator.cs index 3e4aea4385..a361f387e3 100644 --- a/src/Umbraco.Core/PropertyEditors/IValueFormatValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/IValueFormatValidator.cs @@ -14,11 +14,12 @@ namespace Umbraco.Core.PropertyEditors /// The value to validate. /// The value type. /// A format definition. + /// A custom validation message to use when the property value is does not match the specific format (regex). /// Validation results. /// /// The is expected to be a valid regular expression. /// This is used to validate values against the property type validation regular expression. /// - IEnumerable ValidateFormat(object value, string valueType, string format); + IEnumerable ValidateFormat(object value, string valueType, string format, string formatMessage); } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/PropertyEditors/IValueRequiredValidator.cs b/src/Umbraco.Core/PropertyEditors/IValueRequiredValidator.cs index f8e62788c8..7055e1287b 100644 --- a/src/Umbraco.Core/PropertyEditors/IValueRequiredValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/IValueRequiredValidator.cs @@ -13,10 +13,11 @@ namespace Umbraco.Core.PropertyEditors /// /// The value to validate. /// The value type. + /// A custom validation message to use when the property value is required. /// Validation results. /// /// This is used to validate values when the property type specifies that a value is required. /// - IEnumerable ValidateRequired(object value, string valueType); + IEnumerable ValidateRequired(object value, string valueType, string requiredMessage); } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs index e405fa3a3e..53686d745c 100644 --- a/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/Validators/RegexValidator.cs @@ -58,17 +58,28 @@ namespace Umbraco.Core.PropertyEditors.Validators public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) { if (_regex == null) + { throw new InvalidOperationException("The validator has not been configured."); + } - return ValidateFormat(value, valueType, _regex); + return ValidateFormat(value, valueType, _regex, string.Empty); } /// - public IEnumerable ValidateFormat(object value, string valueType, string format) + public IEnumerable ValidateFormat(object value, string valueType, string format, string formatMessage) { - if (string.IsNullOrWhiteSpace(format)) throw new ArgumentNullOrEmptyException(nameof(format)); + if (string.IsNullOrWhiteSpace(format)) + { + throw new ArgumentNullOrEmptyException(nameof(format)); + } + if (value == null || !new Regex(format).IsMatch(value.ToString())) - yield return new ValidationResult(_textService.Localize("validation", "invalidPattern"), new[] { "value" }); + { + var message = string.IsNullOrWhiteSpace(formatMessage) + ? _textService.Localize("validation", "invalidPattern") + : formatMessage; + yield return new ValidationResult(message, new[] { "value" }); + } } } } diff --git a/src/Umbraco.Core/PropertyEditors/Validators/RequiredValidator.cs b/src/Umbraco.Core/PropertyEditors/Validators/RequiredValidator.cs index c51f572817..d752c4ca47 100644 --- a/src/Umbraco.Core/PropertyEditors/Validators/RequiredValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/Validators/RequiredValidator.cs @@ -27,28 +27,40 @@ namespace Umbraco.Core.PropertyEditors.Validators /// public IEnumerable Validate(object value, string valueType, object dataTypeConfiguration) { - return ValidateRequired(value, valueType); + return ValidateRequired(value, valueType, string.Empty); } /// - public IEnumerable ValidateRequired(object value, string valueType) + public IEnumerable ValidateRequired(object value, string valueType, string requiredMessage) { if (value == null) { - yield return new ValidationResult(_textService.Localize("validation", "invalidNull"), new[] {"value"}); + var message = string.IsNullOrWhiteSpace(requiredMessage) + ? _textService.Localize("validation", "invalidNull") + : requiredMessage; + yield return new ValidationResult(message, new[] {"value"}); yield break; } if (valueType.InvariantEquals(ValueTypes.Json)) { + var message = string.IsNullOrWhiteSpace(requiredMessage) + ? _textService.Localize("validation", "invalidEmpty") + : requiredMessage; if (value.ToString().DetectIsEmptyJson()) - yield return new ValidationResult(_textService.Localize("validation", "invalidEmpty"), new[] { "value" }); + { + yield return new ValidationResult(message, new[] { "value" }); + } + yield break; } if (value.ToString().IsNullOrWhiteSpace()) { - yield return new ValidationResult(_textService.Localize("validation", "invalidEmpty"), new[] { "value" }); + var message = string.IsNullOrWhiteSpace(requiredMessage) + ? _textService.Localize("validation", "invalidEmpty") + : requiredMessage; + yield return new ValidationResult(message, new[] { "value" }); } } } diff --git a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs index 863ecc0b1b..d9be4b01b7 100644 --- a/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/Implement/EntityXmlSerializer.cs @@ -360,7 +360,9 @@ namespace Umbraco.Core.Services.Implement new XElement("Definition", definition.Key), new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("Mandatory", propertyType.Mandatory.ToString()), + new XElement("MandatoryMessage", propertyType.MandatoryMessage), new XElement("Validation", propertyType.ValidationRegExp), + new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage), new XElement("Description", new XCData(propertyType.Description))); genericProperties.Add(genericProperty); } @@ -486,7 +488,9 @@ namespace Umbraco.Core.Services.Implement new XElement("Tab", propertyGroup == null ? "" : propertyGroup.Name), new XElement("SortOrder", propertyType.SortOrder), new XElement("Mandatory", propertyType.Mandatory.ToString()), + propertyType.MandatoryMessage != null ? new XElement("MandatoryMessage", propertyType.MandatoryMessage) : null, propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null, + propertyType.ValidationRegExpMessage != null ? new XElement("ValidationRegExpMessage", propertyType.ValidationRegExpMessage) : null, propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null); genericProperties.Add(genericProperty); diff --git a/src/Umbraco.Core/Services/PropertyValidationService.cs b/src/Umbraco.Core/Services/PropertyValidationService.cs index b846095bd1..2e1ba0b8eb 100644 --- a/src/Umbraco.Core/Services/PropertyValidationService.cs +++ b/src/Umbraco.Core/Services/PropertyValidationService.cs @@ -133,7 +133,7 @@ namespace Umbraco.Core.Services var editor = _propertyEditors[propertyType.PropertyEditorAlias]; var configuration = _dataTypeService.GetDataType(propertyType.DataTypeId).Configuration; var valueEditor = editor.GetValueEditor(configuration); - return !valueEditor.Validate(value, propertyType.Mandatory, propertyType.ValidationRegExp).Any(); + return !valueEditor.Validate(value, propertyType.Mandatory, propertyType.MandatoryMessage, propertyType.ValidationRegExp, propertyType.ValidationRegExpMessage).Any(); } } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 7c0e41348b..cbd372cfb6 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -240,6 +240,7 @@ + diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs index 21180ce51b..eee7446823 100644 --- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs +++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs @@ -621,7 +621,9 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation() { Mandatory = true, - Pattern = "xyz" + MandatoryMessage = "Please enter a value", + Pattern = "xyz", + PatternMessage = "Please match the pattern", } }; @@ -634,7 +636,9 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(basic.DataTypeId, result.DataTypeId); Assert.AreEqual(basic.Label, result.Name); Assert.AreEqual(basic.Validation.Mandatory, result.Mandatory); + Assert.AreEqual(basic.Validation.MandatoryMessage, result.MandatoryMessage); Assert.AreEqual(basic.Validation.Pattern, result.ValidationRegExp); + Assert.AreEqual(basic.Validation.PatternMessage, result.ValidationRegExpMessage); } [Test] @@ -655,7 +659,9 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation() { Mandatory = true, - Pattern = "xyz" + MandatoryMessage = "Please enter a value", + Pattern = "xyz", + PatternMessage = "Please match the pattern", } }; @@ -668,7 +674,9 @@ namespace Umbraco.Tests.Models.Mapping Assert.AreEqual(basic.DataTypeId, result.DataTypeId); Assert.AreEqual(basic.Label, result.Name); Assert.AreEqual(basic.Validation.Mandatory, result.Mandatory); + Assert.AreEqual(basic.Validation.MandatoryMessage, result.MandatoryMessage); Assert.AreEqual(basic.Validation.Pattern, result.ValidationRegExp); + Assert.AreEqual(basic.Validation.PatternMessage, result.ValidationRegExpMessage); } [Test] @@ -951,7 +959,7 @@ namespace Umbraco.Tests.Models.Mapping Name = "Tab 1", SortOrder = 0, Inherited = false, - Properties = new [] + Properties = new[] { new MemberPropertyTypeBasic { @@ -965,7 +973,7 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation { Mandatory = false, - Pattern = "" + Pattern = string.Empty }, SortOrder = 0, DataTypeId = 555 @@ -1000,7 +1008,7 @@ namespace Umbraco.Tests.Models.Mapping Name = "Tab 1", SortOrder = 0, Inherited = false, - Properties = new [] + Properties = new[] { new PropertyTypeBasic { @@ -1011,7 +1019,7 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation { Mandatory = false, - Pattern = "" + Pattern = string.Empty }, SortOrder = 0, DataTypeId = 555 @@ -1052,7 +1060,7 @@ namespace Umbraco.Tests.Models.Mapping Name = "Tab 1", SortOrder = 0, Inherited = false, - Properties = new [] + Properties = new[] { new PropertyTypeBasic { @@ -1063,7 +1071,7 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation { Mandatory = false, - Pattern = "" + Pattern = string.Empty }, SortOrder = 0, DataTypeId = 555 @@ -1109,7 +1117,7 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation { Mandatory = false, - Pattern = "" + Pattern = string.Empty }, SortOrder = 0, DataTypeId = 555 @@ -1133,7 +1141,7 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation { Mandatory = false, - Pattern = "" + Pattern = string.Empty }, SortOrder = 0, DataTypeId = 555 @@ -1187,7 +1195,7 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation { Mandatory = false, - Pattern = "" + Pattern = string.Empty }, SortOrder = 0, DataTypeId = 555 @@ -1211,7 +1219,7 @@ namespace Umbraco.Tests.Models.Mapping Validation = new PropertyTypeValidation { Mandatory = false, - Pattern = "" + Pattern = string.Empty }, SortOrder = 0, DataTypeId = 555 diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js index 396699866c..1d04418060 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js @@ -501,7 +501,9 @@ property.dataTypeIcon = propertyModel.dataTypeIcon; property.dataTypeName = propertyModel.dataTypeName; property.validation.mandatory = propertyModel.validation.mandatory; + property.validation.mandatoryMessage = propertyModel.validation.mandatoryMessage; property.validation.pattern = propertyModel.validation.pattern; + property.validation.patternMessage = propertyModel.validation.patternMessage; property.showOnMemberProfile = propertyModel.showOnMemberProfile; property.memberCanEdit = propertyModel.memberCanEdit; property.isSensitiveValue = propertyModel.isSensitiveValue; @@ -592,7 +594,9 @@ propertyState: "init", validation: { mandatory: false, - pattern: null + mandatoryMessage: null, + pattern: null, + patternMessage: null } }; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-group-builder.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-group-builder.less index 4c23aef5f0..36bd00c8cb 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-group-builder.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-group-builder.less @@ -494,11 +494,11 @@ input.umb-group-builder__group-sort-value { font-weight: bold; font-size: 14px; color: @ui-action-type; - - &:hover{ + + &:hover { text-decoration: none; - color:@ui-action-type-hover; - border-color:@ui-action-border-hover; + color: @ui-action-type-hover; + border-color: @ui-action-border-hover; } } @@ -555,7 +555,13 @@ input.umb-group-builder__group-sort-value { overflow: hidden; } - .editor-validation-pattern{ + .editor-validation-message { + min-width: 100%; + min-height: 25px; + margin-top: 4px; + } + + .editor-validation-pattern { border: 1px solid @gray-7; margin: 10px 0 0; padding: 6px; diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index cfbb8b78ab..72abb3ba00 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -528,7 +528,8 @@ input[type="checkbox"][readonly] { .help-inline { display: inline-block; vertical-align: middle; - padding-left: 5px; + padding-top: 4px; + padding-left: 2px; } div.help { diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index 93d7936326..56c2b94bd7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -81,38 +81,55 @@
- +
- -
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js index 32e9891eb4..2bbd7404f7 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js @@ -1,4 +1,4 @@ -function textboxController($scope) { +function textboxController($scope, localizationService) { // macro parameter editor doesn't contains a config object, // so we create a new one to hold any properties if (!$scope.model.config) { @@ -18,6 +18,15 @@ function textboxController($scope) { } } $scope.model.change(); + + $scope.mandatoryMessage = ""; + if ($scope.model.validation.mandatoryMessage) { + $scope.mandatoryMessage = $scope.model.validation.mandatoryMessage; + } else { + localizationService.localize("general_required").then(function (value) { + $scope.mandatoryMessage = value; + }); + } } angular.module('umbraco').controller("Umbraco.PropertyEditors.textboxController", textboxController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.html index 92f02b9f5b..238d70e5e3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.html @@ -7,9 +7,9 @@ ng-trim="false" ng-keyup="model.change()" /> - + {{textboxFieldForm.textbox.errorMsg}} - Required + {{mandatoryMessage}}
diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index 175146aafd..7541297815 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -1951,7 +1951,9 @@ To manage your website, simply open the Umbraco back office and start adding con Validate as a URL ...or enter a custom validation Field is mandatory + Enter a custom validation error message (optional) Enter a regular expression + Enter a custom validation error message (optional) You need to add at least You can only have items diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index 6aa6054992..9357d4720a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -1961,7 +1961,9 @@ To manage your website, simply open the Umbraco back office and start adding con Validate as a URL ...or enter a custom validation Field is mandatory + Enter a custom validation error message (optional) Enter a regular expression + Enter a custom validation error message (optional) You need to add at least You can only have items diff --git a/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs b/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs index 4acf0c948e..67f2e2d090 100644 --- a/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs +++ b/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs @@ -167,7 +167,7 @@ namespace Umbraco.Web.Editors.Filters { // validate var valueEditor = editor.GetValueEditor(property.DataType.Configuration); - foreach (var r in valueEditor.Validate(postedValue, property.IsRequired, property.ValidationRegExp)) + foreach (var r in valueEditor.Validate(postedValue, property.IsRequired, property.IsRequiredMessage, property.ValidationRegExp, property.ValidationRegExpMessage)) { modelState.AddPropertyError(r, property.Alias, property.Culture); } diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs index 1f9d0e9b77..83e5e2a9b2 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentPropertyDto.cs @@ -11,10 +11,17 @@ namespace Umbraco.Web.Models.ContentEditing internal class ContentPropertyDto : ContentPropertyBasic { public IDataType DataType { get; set; } + public string Label { get; set; } + public string Description { get; set; } + public bool IsRequired { get; set; } + + public string IsRequiredMessage { get; set; } + public string ValidationRegExp { get; set; } + public string ValidationRegExpMessage { get; set; } } } diff --git a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeValidation.cs b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeValidation.cs index 929c7ce324..a45af12341 100644 --- a/src/Umbraco.Web/Models/ContentEditing/PropertyTypeValidation.cs +++ b/src/Umbraco.Web/Models/ContentEditing/PropertyTypeValidation.cs @@ -11,7 +11,13 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "mandatory")] public bool Mandatory { get; set; } + [DataMember(Name = "mandatoryMessage")] + public string MandatoryMessage { get; set; } + [DataMember(Name = "pattern")] public string Pattern { get; set; } + + [DataMember(Name = "patternMessage")] + public string PatternMessage { get; set; } } } diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs index 8a45548e9c..535c67bee1 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDisplayMapper.cs @@ -42,7 +42,9 @@ namespace Umbraco.Web.Models.Mapping //add the validation information dest.Validation.Mandatory = originalProp.PropertyType.Mandatory; + dest.Validation.MandatoryMessage = originalProp.PropertyType.MandatoryMessage; dest.Validation.Pattern = originalProp.PropertyType.ValidationRegExp; + dest.Validation.PatternMessage = originalProp.PropertyType.ValidationRegExpMessage; if (dest.PropertyEditor == null) { diff --git a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs index f192cd32ce..472a32f0b1 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentPropertyDtoMapper.cs @@ -21,7 +21,9 @@ namespace Umbraco.Web.Models.Mapping base.Map(property, dest, context); dest.IsRequired = property.PropertyType.Mandatory; + dest.IsRequiredMessage = property.PropertyType.MandatoryMessage; dest.ValidationRegExp = property.PropertyType.ValidationRegExp; + dest.ValidationRegExpMessage = property.PropertyType.ValidationRegExpMessage; dest.Description = property.PropertyType.Description; dest.Label = property.PropertyType.Name; dest.DataType = DataTypeService.GetDataType(property.PropertyType.DataTypeId); diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs index a438f04781..f89e0604b4 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeMapDefinition.cs @@ -220,7 +220,9 @@ namespace Umbraco.Web.Models.Mapping target.Name = source.Label; target.DataTypeId = source.DataTypeId; target.Mandatory = source.Validation.Mandatory; + target.MandatoryMessage = source.Validation.MandatoryMessage; target.ValidationRegExp = source.Validation.Pattern; + target.ValidationRegExpMessage = source.Validation.PatternMessage; target.Variations = source.AllowCultureVariant ? ContentVariation.Culture : ContentVariation.Nothing; if (source.Id > 0) diff --git a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs index 8c5f347799..70074d22a9 100644 --- a/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/PropertyTypeGroupMapper.cs @@ -223,7 +223,13 @@ namespace Umbraco.Web.Models.Mapping Alias = p.Alias, Description = p.Description, Editor = p.PropertyEditorAlias, - Validation = new PropertyTypeValidation {Mandatory = p.Mandatory, Pattern = p.ValidationRegExp}, + Validation = new PropertyTypeValidation + { + Mandatory = p.Mandatory, + MandatoryMessage = p.MandatoryMessage, + Pattern = p.ValidationRegExp, + PatternMessage = p.ValidationRegExpMessage, + }, Label = p.Name, View = propertyEditor.GetValueEditor().View, Config = config, diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs index 6dee2f78b5..f85171304b 100644 --- a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs @@ -313,9 +313,19 @@ namespace Umbraco.Web.PropertyEditors if (propType.Mandatory) { if (propValues[propKey] == null) - yield return new ValidationResult("Item " + (i + 1) + " '" + propType.Name + "' cannot be null", new[] { propKey }); + { + var message = string.IsNullOrWhiteSpace(propType.MandatoryMessage) + ? $"'{propType.Name}' cannot be null" + : propType.MandatoryMessage; + yield return new ValidationResult($"Item {(i + 1)}: {message}", new[] { propKey }); + } else if (propValues[propKey].ToString().IsNullOrWhiteSpace() || (propValues[propKey].Type == JTokenType.Array && !propValues[propKey].HasValues)) - yield return new ValidationResult("Item " + (i + 1) + " '" + propType.Name + "' cannot be empty", new[] { propKey }); + { + var message = string.IsNullOrWhiteSpace(propType.MandatoryMessage) + ? $"'{propType.Name}' cannot be empty" + : propType.MandatoryMessage; + yield return new ValidationResult($"Item{(i + 1)}: {message}", new[] { propKey }); + } } // Check regex @@ -325,7 +335,10 @@ namespace Umbraco.Web.PropertyEditors var regex = new Regex(propType.ValidationRegExp); if (!regex.IsMatch(propValues[propKey].ToString())) { - yield return new ValidationResult("Item " + (i + 1) + " '" + propType.Name + "' is invalid, it does not match the correct pattern", new[] { propKey }); + var message = string.IsNullOrWhiteSpace(propType.ValidationRegExpMessage) + ? $"'{propType.Name}' is invalid, it does not match the correct pattern" + : propType.ValidationRegExpMessage; + yield return new ValidationResult($"Item {(i + 1)}: {message}", new[] { propKey }); } } } diff --git a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs index 90527a8b8d..508f4d03e8 100644 --- a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs @@ -57,7 +57,7 @@ namespace Umbraco.Web.PropertyEditors private class RequiredJsonValueValidator : IValueRequiredValidator { /// - public IEnumerable ValidateRequired(object value, string valueType) + public IEnumerable ValidateRequired(object value, string valueType, string requiredMessage) { if (value == null) { From bb3d2cd948703196f2df883049a1dffba107d938 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Thu, 27 Jun 2019 15:10:27 +0200 Subject: [PATCH 02/15] Applied custom mandatory validation message to existing core property editors that support the mandatory setting. --- .../services/validationhelper.service.js | 30 +++++++++++++ .../colorpicker/colorpicker.controller.js | 2 +- .../datepicker/datepicker.controller.js | 7 +++- .../datepicker/datepicker.html | 2 +- .../dropdownFlexible.controller.js | 8 +++- .../dropdownFlexible/dropdownFlexible.html | 42 +++++++++++-------- .../propertyeditors/email/email.controller.js | 10 +++++ .../views/propertyeditors/email/email.html | 4 +- .../radiobuttons/radiobuttons.controller.js | 8 +++- .../radiobuttons/radiobuttons.html | 18 +++++--- .../textbox/textbox.controller.js | 16 +++---- 11 files changed, 108 insertions(+), 39 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js new file mode 100644 index 0000000000..0ab8e9fdb9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js @@ -0,0 +1,30 @@ +(function () { + 'use strict'; + + function validationHelperService($q, localizationService) { + + // Gets the message to use for when a mandatory field isn't completed. + // Will either use the one provided on the property type's validation object + // or a localised default. + function getMandatoryMessage(validation) { + if (validation.mandatoryMessage) { + return $q.when(validation.mandatoryMessage); + } else { + return localizationService.localize("general_required").then(function (value) { + return $q.when(value); + }); + } + } + + var service = { + getMandatoryMessage: getMandatoryMessage + }; + + return service; + + } + + angular.module('umbraco.services').factory('validationHelper', validationHelperService); + + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js index d6fe709962..937e4e787b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/colorpicker/colorpicker.controller.js @@ -110,7 +110,7 @@ function ColorPickerController($scope) { ); return { isValid: isValid, - errorMsg: "Value cannot be empty", + errorMsg: $scope.model.validation.mandatoryMessage || "Value cannot be empty", errorKey: "required" }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index 62099734fb..092f6411e8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -1,4 +1,4 @@ -function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService, $element, dateHelper) { +function dateTimePickerController($scope, angularHelper, dateHelper, validationHelper) { let flatPickr = null; @@ -56,6 +56,11 @@ function dateTimePickerController($scope, notificationsService, assetsService, a setDatePickerVal(); + // Set the message to use for when a mandatory field isn't completed. + // Will either use the one provided on the property type or a localised default. + validationHelper.getMandatoryMessage($scope.model.validation).then(function (value) { + $scope.mandatoryMessage = value; + }); } $scope.clearDate = function() { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html index 0d3fad580e..77719e4421 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html @@ -32,7 +32,7 @@
- Required + {{mandatoryMessage}} {{datePickerForm.datepicker.errorMsg}} Invalid date diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js index 3b341f7ac0..d842b3b006 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.controller.js @@ -1,5 +1,5 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleController", - function($scope) { + function ($scope, validationHelper) { //setup the default config var config = { @@ -89,4 +89,10 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleCo $scope.model.value = null; } } + + // Set the message to use for when a mandatory field isn't completed. + // Will either use the one provided on the property type or a localised default. + validationHelper.getMandatoryMessage($scope.model.validation).then(function (value) { + $scope.mandatoryMessage = value; + }); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html index 5f873e9e43..617d841139 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html @@ -1,21 +1,29 @@
- + + + - - + + + + + {{mandatoryMessage}} + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.controller.js new file mode 100644 index 0000000000..9c8a581dd4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.controller.js @@ -0,0 +1,10 @@ +function emailController($scope, validationHelper) { + + // Set the message to use for when a mandatory field isn't completed. + // Will either use the one provided on the property type or a localised default. + validationHelper.getMandatoryMessage($scope.model.validation).then(function(value) { + $scope.mandatoryMessage = value; + }); + +} +angular.module('umbraco').controller("Umbraco.PropertyEditors.EmailController", emailController); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html index 881ad37d7c..8576d179f2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html @@ -1,4 +1,4 @@ -
+
- Required + {{mandatoryMessage}} Invalid email {{emailFieldForm.textbox.errorMsg}} diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.controller.js index 3a96b6573a..13baf27f8a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.controller.js @@ -1,5 +1,5 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.RadioButtonsController", - function($scope) { + function ($scope, validationHelper) { function init() { @@ -19,6 +19,12 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.RadioButtonsContro $scope.configItems = configItems; } + + // Set the message to use for when a mandatory field isn't completed. + // Will either use the one provided on the property type or a localised default. + validationHelper.getMandatoryMessage($scope.model.validation).then(function (value) { + $scope.mandatoryMessage = value; + }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html index 8c5f2a22d3..b5e55adebd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html @@ -1,7 +1,15 @@ 
-
    -
  • - -
  • -
+ + +
    +
  • + +
  • +
+ + + {{mandatoryMessage}} + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js index 2bbd7404f7..feb0148849 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/textbox/textbox.controller.js @@ -1,4 +1,4 @@ -function textboxController($scope, localizationService) { +function textboxController($scope, validationHelper) { // macro parameter editor doesn't contains a config object, // so we create a new one to hold any properties if (!$scope.model.config) { @@ -19,14 +19,10 @@ function textboxController($scope, localizationService) { } $scope.model.change(); - $scope.mandatoryMessage = ""; - if ($scope.model.validation.mandatoryMessage) { - $scope.mandatoryMessage = $scope.model.validation.mandatoryMessage; - } else { - localizationService.localize("general_required").then(function (value) { - $scope.mandatoryMessage = value; - }); - } - + // Set the message to use for when a mandatory field isn't completed. + // Will either use the one provided on the property type or a localised default. + validationHelper.getMandatoryMessage($scope.model.validation).then(function(value) { + $scope.mandatoryMessage = value; + }); } angular.module('umbraco').controller("Umbraco.PropertyEditors.textboxController", textboxController); From 011ad47ac0709227aa3e7313966fb7c022b6d3ce Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Thu, 27 Jun 2019 20:00:52 +0200 Subject: [PATCH 03/15] Updated new ng-messsages elements to use tags introduced in main branch --- .../views/propertyeditors/datepicker/datepicker.html | 10 +++++----- .../dropdownFlexible/dropdownFlexible.html | 6 +++--- .../src/views/propertyeditors/email/email.html | 10 +++++----- .../propertyeditors/radiobuttons/radiobuttons.html | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html index 3142f078ec..0f3ae8f510 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html @@ -32,11 +32,11 @@
- - {{mandatoryMessage}} - {{datePickerForm.datepicker.errorMsg}} - Invalid date - +
+

{{mandatoryMessage}}

+

{{datePickerForm.datepicker.errorMsg}}

+

Invalid date

+

This translates to the following time on the server: {{serverTime}}
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html index 617d841139..1059df2994 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/dropdownFlexible/dropdownFlexible.html @@ -21,9 +21,9 @@ ng-options="item.value as item.value for item in model.config.items" ng-required="model.validation.mandatory"> - - {{mandatoryMessage}} - +

+

{{mandatoryMessage}}

+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html index 8576d179f2..26ec22df8d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/email/email.html @@ -8,10 +8,10 @@ ng-required="model.config.IsRequired || model.validation.mandatory" val-server="value" /> - - {{mandatoryMessage}} - Invalid email - {{emailFieldForm.textbox.errorMsg}} - +
+

{{mandatoryMessage}}

+

Invalid email

+

{{emailFieldForm.textbox.errorMsg}}

+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html index b5e55adebd..c4c76e0b40 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/radiobuttons/radiobuttons.html @@ -7,9 +7,9 @@ - - {{mandatoryMessage}} - +
+

{{mandatoryMessage}}

+
From 1168197e6652eea6cbbd11a488740d29a27e2a6f Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Thu, 27 Jun 2019 23:20:40 +0200 Subject: [PATCH 04/15] Fixed formatting of nested content validation --- src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs index f85171304b..c4b0333c2d 100644 --- a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs @@ -324,7 +324,7 @@ namespace Umbraco.Web.PropertyEditors var message = string.IsNullOrWhiteSpace(propType.MandatoryMessage) ? $"'{propType.Name}' cannot be empty" : propType.MandatoryMessage; - yield return new ValidationResult($"Item{(i + 1)}: {message}", new[] { propKey }); + yield return new ValidationResult($"Item {(i + 1)}: {message}", new[] { propKey }); } } From 8fe25ff781e2b0301f29054a4f67fde741698ce5 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Fri, 28 Jun 2019 14:46:28 +0200 Subject: [PATCH 05/15] Added null check to resolve failing front-end unit test --- .../src/common/services/validationhelper.service.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js index 0ab8e9fdb9..16ea5a60a5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js @@ -7,6 +7,10 @@ // Will either use the one provided on the property type's validation object // or a localised default. function getMandatoryMessage(validation) { + if (!validation) { + return $q.when(""); + } + if (validation.mandatoryMessage) { return $q.when(validation.mandatoryMessage); } else { From 973117df581aea9c6725ea658f3c1612b863affb Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 30 Sep 2019 20:16:29 +0200 Subject: [PATCH 06/15] Updated migration plan to move validation messages into migration to 8.3 --- src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs | 1 + .../AddPropertyTypeValidationMessageColumns.cs | 0 2 files changed, 1 insertion(+) rename src/Umbraco.Core/Migrations/Upgrade/{V_8_1_0 => V_8_3_0}/AddPropertyTypeValidationMessageColumns.cs (100%) diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index cf9e0f7b67..a328a13bed 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Migrations.Upgrade.Common; using Umbraco.Core.Migrations.Upgrade.V_8_0_0; using Umbraco.Core.Migrations.Upgrade.V_8_0_1; using Umbraco.Core.Migrations.Upgrade.V_8_1_0; +using Umbraco.Core.Migrations.Upgrade.V_8_3_0; namespace Umbraco.Core.Migrations.Upgrade { diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/AddPropertyTypeValidationMessageColumns.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_3_0/AddPropertyTypeValidationMessageColumns.cs similarity index 100% rename from src/Umbraco.Core/Migrations/Upgrade/V_8_1_0/AddPropertyTypeValidationMessageColumns.cs rename to src/Umbraco.Core/Migrations/Upgrade/V_8_3_0/AddPropertyTypeValidationMessageColumns.cs From 133704db7bfd626b0c39cdca3542bc77def566ba Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 30 Sep 2019 20:22:13 +0200 Subject: [PATCH 07/15] Update validation message fields to single-line inputs --- .../propertysettings/propertysettings.html | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index ed183e3a03..4474390199 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -94,14 +94,14 @@ focus-when="{{vm.focusOnMandatoryField}}" - + +
internal sealed class ContentSaveValidationAttribute : ActionFilterAttribute { - public ContentSaveValidationAttribute(): this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.ContentService, Current.Services.UserService, Current.Services.EntityService) + private readonly ILogger _logger; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly ILocalizedTextService _textService; + private readonly IContentService _contentService; + private readonly IUserService _userService; + private readonly IEntityService _entityService; + + public ContentSaveValidationAttribute(): this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.ContentService, Current.Services.UserService, Current.Services.EntityService) { } - public ContentSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, IContentService contentService, IUserService userService, IEntityService entityService) + public ContentSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, IEntityService entityService) { - _logger = logger; - _umbracoContextAccessor = umbracoContextAccessor; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _textService = textService ?? throw new ArgumentNullException(nameof(textService)); _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); } - private readonly ILogger _logger; - private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly IContentService _contentService; - private readonly IUserService _userService; - private readonly IEntityService _entityService; - public override void OnActionExecuting(HttpActionContext actionContext) { var model = (ContentItemSave)actionContext.ActionArguments["contentItem"]; - var contentItemValidator = new ContentSaveModelValidator(_logger, _umbracoContextAccessor); + var contentItemValidator = new ContentSaveModelValidator(_logger, _umbracoContextAccessor, _textService); if (!ValidateAtLeastOneVariantIsBeingSaved(model, actionContext)) return; if (!contentItemValidator.ValidateExistingContent(model, actionContext)) return; diff --git a/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs index 7351c476e4..449ef95675 100644 --- a/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs @@ -1,7 +1,6 @@ -using System.Linq; +using System; using System.Net; using System.Net.Http; -using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; using Umbraco.Core; @@ -21,25 +20,27 @@ namespace Umbraco.Web.Editors.Filters { private readonly ILogger _logger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly ILocalizedTextService _textService; private readonly IMediaService _mediaService; private readonly IEntityService _entityService; - public MediaItemSaveValidationAttribute() : this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.MediaService, Current.Services.EntityService) + public MediaItemSaveValidationAttribute() : this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.MediaService, Current.Services.EntityService) { } - public MediaItemSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, IMediaService mediaService, IEntityService entityService) + public MediaItemSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IMediaService mediaService, IEntityService entityService) { - _logger = logger; - _umbracoContextAccessor = umbracoContextAccessor; - _mediaService = mediaService; - _entityService = entityService; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _textService = textService ?? throw new ArgumentNullException(nameof(textService)); + _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); + _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); } public override void OnActionExecuting(HttpActionContext actionContext) { var model = (MediaItemSave)actionContext.ActionArguments["contentItem"]; - var contentItemValidator = new MediaSaveModelValidator(_logger, _umbracoContextAccessor); + var contentItemValidator = new MediaSaveModelValidator(_logger, _umbracoContextAccessor, _textService); if (ValidateUserAccess(model, actionContext)) { diff --git a/src/Umbraco.Web/Editors/Filters/MediaSaveModelValidator.cs b/src/Umbraco.Web/Editors/Filters/MediaSaveModelValidator.cs index 83c0885d62..87b55fea76 100644 --- a/src/Umbraco.Web/Editors/Filters/MediaSaveModelValidator.cs +++ b/src/Umbraco.Web/Editors/Filters/MediaSaveModelValidator.cs @@ -1,5 +1,6 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Editors.Filters @@ -9,8 +10,8 @@ namespace Umbraco.Web.Editors.Filters /// internal class MediaSaveModelValidator : ContentModelValidator> { - public MediaSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, umbracoContextAccessor) + public MediaSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService) : base(logger, umbracoContextAccessor, textService) { } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Web/Editors/Filters/MemberSaveModelValidator.cs b/src/Umbraco.Web/Editors/Filters/MemberSaveModelValidator.cs index 7fc2b1e648..9b47965493 100644 --- a/src/Umbraco.Web/Editors/Filters/MemberSaveModelValidator.cs +++ b/src/Umbraco.Web/Editors/Filters/MemberSaveModelValidator.cs @@ -21,10 +21,10 @@ namespace Umbraco.Web.Editors.Filters { private readonly IMemberTypeService _memberTypeService; - public MemberSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, IMemberTypeService memberTypeService) - : base(logger, umbracoContextAccessor) + public MemberSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IMemberTypeService memberTypeService) + : base(logger, umbracoContextAccessor, textService) { - _memberTypeService = memberTypeService; + _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); } /// diff --git a/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs index 04b0112d56..7e2c204596 100644 --- a/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/MemberSaveValidationAttribute.cs @@ -1,4 +1,5 @@ -using System.Web.Http.Controllers; +using System; +using System.Web.Http.Controllers; using System.Web.Http.Filters; using Umbraco.Core.Logging; using Umbraco.Core.Services; @@ -14,23 +15,25 @@ namespace Umbraco.Web.Editors.Filters { private readonly ILogger _logger; private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly ILocalizedTextService _textService; private readonly IMemberTypeService _memberTypeService; public MemberSaveValidationAttribute() - : this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.MemberTypeService) + : this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.MemberTypeService) { } - public MemberSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, IMemberTypeService memberTypeService) + public MemberSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IMemberTypeService memberTypeService) { - _logger = logger; - _umbracoContextAccessor = umbracoContextAccessor; - _memberTypeService = memberTypeService; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); + _textService = textService ?? throw new ArgumentNullException(nameof(textService)); + _memberTypeService = memberTypeService ?? throw new ArgumentNullException(nameof(memberTypeService)); } public override void OnActionExecuting(HttpActionContext actionContext) { var model = (MemberSave)actionContext.ActionArguments["contentItem"]; - var contentItemValidator = new MemberSaveModelValidator(_logger, _umbracoContextAccessor, _memberTypeService); + var contentItemValidator = new MemberSaveModelValidator(_logger, _umbracoContextAccessor, _textService, _memberTypeService); //now do each validation step if (contentItemValidator.ValidateExistingContent(model, actionContext)) if (contentItemValidator.ValidateProperties(model, model, actionContext)) diff --git a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs index 250f1a665a..fd7e8694a3 100644 --- a/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TagsPropertyEditor.cs @@ -77,7 +77,7 @@ namespace Umbraco.Web.PropertyEditors private class RequiredJsonValueValidator : IValueRequiredValidator { /// - public IEnumerable ValidateRequired(object value, string valueType, string requiredMessage) + public IEnumerable ValidateRequired(object value, string valueType) { if (value == null) { From d25a38e448d229d25eac26440b95b7fbf22da381 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Wed, 9 Oct 2019 08:15:27 +0200 Subject: [PATCH 12/15] Renamed client-side service file to match function name --- .../{validationhelper.service.js => validationmessage.service.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Umbraco.Web.UI.Client/src/common/services/{validationhelper.service.js => validationmessage.service.js} (100%) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/validationmessage.service.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/common/services/validationhelper.service.js rename to src/Umbraco.Web.UI.Client/src/common/services/validationmessage.service.js From 4e95e13c5d06af5f3da9c33c12ddc931443e4450 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Sat, 12 Oct 2019 15:13:57 +0200 Subject: [PATCH 13/15] Reverted a comment update now interface change has also been reverted. --- src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs index c0e6d548f0..041d3f6422 100644 --- a/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueEditor.cs @@ -40,7 +40,7 @@ namespace Umbraco.Core.PropertyEditors bool CanCopy { get; } /// - /// Validates a property value using custom messages. + /// Validates a property value. /// /// The property value. /// A value indicating whether the property value is required. From e934dbd054ee2017d1ef5fd6a6d705d73fe35724 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Fri, 1 Nov 2019 09:38:41 +0100 Subject: [PATCH 14/15] Updated validation message comparisons with default messages to use invariant comparison. --- src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs b/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs index 22f52e9293..0d77b35528 100644 --- a/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs +++ b/src/Umbraco.Web/Editors/Filters/ContentModelValidator.cs @@ -188,12 +188,12 @@ namespace Umbraco.Web.Editors.Filters foreach (var r in valueEditor.Validate(postedValue, property.IsRequired, property.ValidationRegExp)) { // If we've got custom error messages, we'll replace the default ones that will have been applied in the call to Validate(). - if (property.IsRequired && !string.IsNullOrWhiteSpace(property.IsRequiredMessage) && requiredDefaultMessages.Contains(r.ErrorMessage)) + if (property.IsRequired && !string.IsNullOrWhiteSpace(property.IsRequiredMessage) && requiredDefaultMessages.Contains(r.ErrorMessage, StringComparer.OrdinalIgnoreCase)) { r.ErrorMessage = property.IsRequiredMessage; } - if (!string.IsNullOrWhiteSpace(property.ValidationRegExp) && !string.IsNullOrWhiteSpace(property.ValidationRegExpMessage) && formatDefaultMessages.Contains(r.ErrorMessage)) + if (!string.IsNullOrWhiteSpace(property.ValidationRegExp) && !string.IsNullOrWhiteSpace(property.ValidationRegExpMessage) && formatDefaultMessages.Contains(r.ErrorMessage, StringComparer.OrdinalIgnoreCase)) { r.ErrorMessage = property.ValidationRegExpMessage; } From 54b3e7e60d7ca45df9143487b6e62a5064bb7317 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 19 Nov 2019 12:35:36 +0100 Subject: [PATCH 15/15] Moved custom validation message database migrations into 8.4 folder and namespace --- src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs | 2 +- .../AddPropertyTypeValidationMessageColumns.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/Umbraco.Core/Migrations/Upgrade/{V_8_3_0 => V_8_4_0}/AddPropertyTypeValidationMessageColumns.cs (92%) diff --git a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs index a328a13bed..d1da2ef3e0 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/UmbracoPlan.cs @@ -6,7 +6,7 @@ using Umbraco.Core.Migrations.Upgrade.Common; using Umbraco.Core.Migrations.Upgrade.V_8_0_0; using Umbraco.Core.Migrations.Upgrade.V_8_0_1; using Umbraco.Core.Migrations.Upgrade.V_8_1_0; -using Umbraco.Core.Migrations.Upgrade.V_8_3_0; +using Umbraco.Core.Migrations.Upgrade.V_8_4_0; namespace Umbraco.Core.Migrations.Upgrade { diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_3_0/AddPropertyTypeValidationMessageColumns.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_4_0/AddPropertyTypeValidationMessageColumns.cs similarity index 92% rename from src/Umbraco.Core/Migrations/Upgrade/V_8_3_0/AddPropertyTypeValidationMessageColumns.cs rename to src/Umbraco.Core/Migrations/Upgrade/V_8_4_0/AddPropertyTypeValidationMessageColumns.cs index ac3f959377..4eb0931979 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_3_0/AddPropertyTypeValidationMessageColumns.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_4_0/AddPropertyTypeValidationMessageColumns.cs @@ -1,7 +1,7 @@ using System.Linq; using Umbraco.Core.Persistence.Dtos; -namespace Umbraco.Core.Migrations.Upgrade.V_8_3_0 +namespace Umbraco.Core.Migrations.Upgrade.V_8_4_0 { public class AddPropertyTypeValidationMessageColumns : MigrationBase { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 999b69cc9a..08e4d6081a 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -260,7 +260,7 @@ - + @@ -1573,4 +1573,4 @@ - + \ No newline at end of file