Merge branch 'AndyButland-feature/5702-custom-validation-messages' into v8/dev
This commit is contained in:
@@ -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_6_0;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade
|
||||
{
|
||||
@@ -182,6 +183,9 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<RenameUserLoginDtoDateIndex>("{0372A42B-DECF-498D-B4D1-6379E907EB94}");
|
||||
To<FixContentNuCascade>("{5B1E0D93-F5A3-449B-84BA-65366B84E2D4}");
|
||||
|
||||
// to 8.6.0
|
||||
To<AddPropertyTypeValidationMessageColumns>("{3D67D2C8-5E65-47D0-A9E1-DC2EE0779D6B}");
|
||||
|
||||
//FINAL
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_6_0
|
||||
{
|
||||
public class AddPropertyTypeValidationMessageColumns : MigrationBase
|
||||
{
|
||||
public AddPropertyTypeValidationMessageColumns(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToList();
|
||||
|
||||
AddColumnIfNotExists<PropertyTypeDto>(columns, "mandatoryMessage");
|
||||
AddColumnIfNotExists<PropertyTypeDto>(columns, "validationRegExpMessage");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,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;
|
||||
|
||||
/// <summary>
|
||||
@@ -183,7 +185,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool Mandatory
|
||||
@@ -192,6 +194,16 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _mandatory, nameof(Mandatory));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom validation message used when a value for this PropertyType is required
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string MandatoryMessage
|
||||
{
|
||||
get => _mandatoryMessage;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _mandatoryMessage, nameof(MandatoryMessage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets of sets the sort order of the property type.
|
||||
/// </summary>
|
||||
@@ -212,6 +224,16 @@ namespace Umbraco.Core.Models
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _validationRegExp, nameof(ValidationRegExp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the custom validation message used when a pattern for this PropertyType must be matched
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string ValidationRegExpMessage
|
||||
{
|
||||
get => _validationRegExpMessage;
|
||||
set => SetPropertyValueAndDetectChanges(value, ref _validationRegExpMessage, nameof(ValidationRegExpMessage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content variation of the property type.
|
||||
/// </summary>
|
||||
|
||||
@@ -787,7 +787,14 @@ namespace Umbraco.Core.Packaging
|
||||
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,
|
||||
Variations = property.Element("Variations") != null
|
||||
? (ContentVariation)Enum.Parse(typeof(ContentVariation), property.Element("Variations").Value)
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -60,8 +60,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<int>(() => tempGroupDto.Id);
|
||||
propertyType.CreateDate = createDate;
|
||||
propertyType.UpdateDate = updateDate;
|
||||
@@ -124,9 +126,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
|
||||
};
|
||||
|
||||
@@ -24,9 +24,11 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.DataTypeId), nameof(PropertyTypeDto.DataTypeId));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Description), nameof(PropertyTypeDto.Description));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Mandatory), nameof(PropertyTypeDto.Mandatory));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.MandatoryMessage), nameof(PropertyTypeDto.MandatoryMessage));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.Name), nameof(PropertyTypeDto.Name));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.SortOrder), nameof(PropertyTypeDto.SortOrder));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.ValidationRegExp), nameof(PropertyTypeDto.ValidationRegExp));
|
||||
DefineMap<PropertyType, PropertyTypeDto>(nameof(PropertyType.ValidationRegExpMessage), nameof(PropertyTypeDto.ValidationRegExpMessage));
|
||||
DefineMap<PropertyType, DataTypeDto>(nameof(PropertyType.PropertyEditorAlias), nameof(DataTypeDto.EditorAlias));
|
||||
DefineMap<PropertyType, DataTypeDto>(nameof(PropertyType.ValueStorageType), nameof(DataTypeDto.DbType));
|
||||
}
|
||||
|
||||
@@ -297,10 +297,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<int>(() => groupId.Value) : null,
|
||||
SortOrder = dto.SortOrder,
|
||||
ValidationRegExp = dto.ValidationRegExp,
|
||||
ValidationRegExpMessage = dto.ValidationRegExpMessage,
|
||||
Variations = (ContentVariation)dto.Variations
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </remarks>
|
||||
IEnumerable<ValidationResult> ValidateFormat(object value, string valueType, string format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// </remarks>
|
||||
IEnumerable<ValidationResult> ValidateRequired(object value, string valueType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,9 @@ namespace Umbraco.Core.PropertyEditors.Validators
|
||||
public IEnumerable<ValidationResult> Validate(object value, string valueType, object dataTypeConfiguration)
|
||||
{
|
||||
if (_regex == null)
|
||||
{
|
||||
throw new InvalidOperationException("The validator has not been configured.");
|
||||
}
|
||||
|
||||
return ValidateFormat(value, valueType, _regex);
|
||||
}
|
||||
@@ -68,9 +70,10 @@ namespace Umbraco.Core.PropertyEditors.Validators
|
||||
{
|
||||
if (format == null) throw new ArgumentNullException(nameof(format));
|
||||
if (string.IsNullOrWhiteSpace(format)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(format));
|
||||
|
||||
if (value == null || !new Regex(format).IsMatch(value.ToString()))
|
||||
{
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidPattern"), new[] { "value" });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,17 @@ namespace Umbraco.Core.PropertyEditors.Validators
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidNull"), new[] {"value"});
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidNull"), new[] { "value" });
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (valueType.InvariantEquals(ValueTypes.Json))
|
||||
{
|
||||
if (value.ToString().DetectIsEmptyJson())
|
||||
{
|
||||
yield return new ValidationResult(_textService.Localize("validation", "invalidEmpty"), new[] { "value" });
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -487,7 +489,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,
|
||||
new XElement("Variations", propertyType.Variations.ToString()));
|
||||
|
||||
|
||||
@@ -260,6 +260,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameMediaVersionTable.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\ValueListPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\UmbracoSliderPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_6_0\AddPropertyTypeValidationMessageColumns.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_1_0\FixContentNuCascade.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_1_0\RenameUserLoginDtoDateIndex.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_1\ChangeNuCacheJsonFormat.cs" />
|
||||
@@ -1572,4 +1573,4 @@
|
||||
<Folder Include="Auditing\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -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
|
||||
|
||||
@@ -549,7 +549,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;
|
||||
@@ -632,7 +634,9 @@
|
||||
propertyState: "init",
|
||||
validation: {
|
||||
mandatory: false,
|
||||
pattern: null
|
||||
mandatoryMessage: null,
|
||||
pattern: null,
|
||||
patternMessage: null
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function validationMessageService($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) {
|
||||
return $q.when("");
|
||||
}
|
||||
|
||||
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('validationMessageService', validationMessageService);
|
||||
|
||||
|
||||
})();
|
||||
@@ -493,11 +493,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +554,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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -81,39 +81,55 @@
|
||||
</div>
|
||||
|
||||
<div class="umb-control-group clearfix" ng-if="!model.property.locked">
|
||||
|
||||
|
||||
<h5><localize key="validation_validation"></localize></h5>
|
||||
|
||||
<label>
|
||||
|
||||
<label>
|
||||
<localize key="validation_fieldIsMandatory"></localize>
|
||||
</label>
|
||||
|
||||
<umb-toggle data-element="validation_mandatory"
|
||||
checked="model.property.validation.mandatory"
|
||||
on-click="vm.toggleValidation()"
|
||||
on-click="vm.toggleValidation()">
|
||||
focus-when="{{vm.focusOnMandatoryField}}"
|
||||
>
|
||||
</umb-toggle>
|
||||
|
||||
<label class="mt3">
|
||||
<input type="text"
|
||||
class="editor-validation-message"
|
||||
localize="placeholder"
|
||||
placeholder="@validation_mandatoryMessage"
|
||||
ng-model="model.property.validation.mandatoryMessage"
|
||||
ng-if="model.property.validation.mandatory"
|
||||
ng-keypress="vm.submitOnEnter($event)">
|
||||
</input>
|
||||
|
||||
<label class="mt3">
|
||||
<localize key="validation_customValidation"></localize>
|
||||
</label>
|
||||
|
||||
|
||||
<select class="umb-dropdown" ng-options="validationType.name for validationType in vm.validationTypes" ng-model="vm.selectedValidationType" ng-change="vm.changeValidationType(vm.selectedValidationType)">
|
||||
<option value=""><localize key="validation_noValidation">No validation</localize></option>
|
||||
</select>
|
||||
|
||||
|
||||
<textarea class="editor-validation-pattern"
|
||||
localize="placeholder"
|
||||
placeholder="@validation_validationRegExp"
|
||||
ng-model="model.property.validation.pattern"
|
||||
ng-change="vm.changeValidationPattern()"
|
||||
ng-if="vm.showValidationPattern"
|
||||
umb-auto-resize
|
||||
focus-when="{{vm.focusOnPatternField}}"
|
||||
ng-keypress="vm.submitOnEnter($event)">
|
||||
</textarea>
|
||||
|
||||
localize="placeholder"
|
||||
placeholder="@validation_validationRegExp"
|
||||
ng-model="model.property.validation.pattern"
|
||||
ng-change="vm.changeValidationPattern()"
|
||||
ng-if="vm.showValidationPattern"
|
||||
umb-auto-resize
|
||||
focus-when="{{vm.focusOnPatternField}}"
|
||||
ng-keypress="vm.submitOnEnter($event)">
|
||||
</textarea>
|
||||
|
||||
<input type="text"
|
||||
class="editor-validation-message"
|
||||
localize="placeholder"
|
||||
placeholder="@validation_validationRegExpMessage"
|
||||
ng-model="model.property.validation.patternMessage"
|
||||
ng-if="vm.showValidationPattern"
|
||||
ng-keypress="vm.submitOnEnter($event)" />
|
||||
|
||||
</div>
|
||||
<div class="umb-control-group clearfix" ng-if="model.contentType === 'documentType' && model.contentTypeAllowCultureVariant">
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ function ColorPickerController($scope, $timeout) {
|
||||
);
|
||||
return {
|
||||
isValid: isValid,
|
||||
errorMsg: "Value cannot be empty",
|
||||
errorMsg: $scope.model.validation.mandatoryMessage || "Value cannot be empty",
|
||||
errorKey: "required"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService, $element, dateHelper) {
|
||||
function dateTimePickerController($scope, angularHelper, dateHelper, validationMessageService) {
|
||||
|
||||
let flatPickr = null;
|
||||
|
||||
@@ -62,6 +62,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.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.clearDate = function() {
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
|
||||
</div>
|
||||
|
||||
<span ng-messages="datePickerForm.datepicker.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valServer">{{datePickerForm.datepicker.errorMsg}}</span>
|
||||
<span class="help-inline" ng-message="pickerError"><localize key="validation_invalidDate">Invalid date</localize></span>
|
||||
</span>
|
||||
<div ng-messages="datePickerForm.datepicker.$error" show-validation-on-submit >
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
<p class="help-inline" ng-message="valServer">{{datePickerForm.datepicker.errorMsg}}</p>
|
||||
<p class="help-inline" ng-message="pickerError"><localize key="validation_invalidDate">Invalid date</localize></p>
|
||||
</div>
|
||||
|
||||
<p ng-if="model.config.offsetTime === '1' && serverTimeNeedsOffsetting && model.value" class="muted">
|
||||
<small><localize key="content_scheduledPublishServerTime">This translates to the following time on the server:</localize> {{serverTime}}</small><br />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleController",
|
||||
function($scope) {
|
||||
function ($scope, validationMessageService) {
|
||||
|
||||
//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.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.DropdownFlexibleController" ng-switch="model.config.multiple">
|
||||
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-default
|
||||
ng-change="updateSingleDropdownValue()"
|
||||
ng-model="model.singleDropdownValue"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory">
|
||||
<option></option>
|
||||
</select>
|
||||
<ng-form name="dropDownListForm">
|
||||
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-default
|
||||
ng-change="updateSingleDropdownValue()"
|
||||
ng-model="model.singleDropdownValue"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory">
|
||||
<option></option>
|
||||
</select>
|
||||
|
||||
<!--NOTE: This ng-switch is required because ng-multiple doesn't actually support dynamic bindings with multi-select lists -->
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-when="true"
|
||||
multiple
|
||||
ng-model="model.value"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory"></select>
|
||||
<!--NOTE: This ng-switch is required because ng-multiple doesn't actually support dynamic bindings with multi-select lists -->
|
||||
<select name="dropDownList"
|
||||
class="umb-property-editor umb-dropdown"
|
||||
ng-switch-when="true"
|
||||
multiple
|
||||
ng-model="model.value"
|
||||
ng-options="item.value as item.value for item in model.config.items"
|
||||
ng-required="model.validation.mandatory"></select>
|
||||
|
||||
<div ng-messages="dropDownListForm.dropDownList.$error" show-validation-on-submit>
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
function emailController($scope, validationMessageService) {
|
||||
|
||||
// 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.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function(value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.EmailController", emailController);
|
||||
@@ -1,4 +1,4 @@
|
||||
<div>
|
||||
<div ng-controller="Umbraco.PropertyEditors.EmailController">
|
||||
<ng-form name="emailFieldForm">
|
||||
<input type="email" name="textbox"
|
||||
ng-model="model.value"
|
||||
@@ -8,10 +8,10 @@
|
||||
ng-required="model.config.IsRequired || model.validation.mandatory"
|
||||
val-server="value" />
|
||||
|
||||
<span ng-messages="emailFieldForm.textbox.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valEmail"><localize key="validation_invalidEmail">Invalid email</localize></span>
|
||||
<span class="help-inline" ng-message="valServer">{{emailFieldForm.textbox.errorMsg}}</span>
|
||||
</span>
|
||||
<div ng-messages="emailFieldForm.textbox.$error" show-validation-on-submit >
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
<p class="help-inline" ng-message="valEmail"><localize key="validation_invalidEmail">Invalid email</localize></p>
|
||||
<p class="help-inline" ng-message="valServer">{{emailFieldForm.textbox.errorMsg}}</p>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.RadioButtonsController",
|
||||
function ($scope) {
|
||||
function ($scope, validationMessageService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -23,6 +23,12 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.RadioButtonsContro
|
||||
|
||||
vm.viewItems = sortedItems;
|
||||
}
|
||||
|
||||
// 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.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
<div class="umb-property-editor umb-radiobuttons" ng-controller="Umbraco.PropertyEditors.RadioButtonsController as vm">
|
||||
<ul class="unstyled">
|
||||
<li ng-repeat="item in vm.viewItems track by item.key">
|
||||
<umb-radiobutton name="{{model.alias}}" value="{{item.value}}" model="model.value" text="{{item.value}}" required="model.validation.mandatory && model.value == ''"></umb-radiobutton>
|
||||
</li>
|
||||
</ul>
|
||||
<ng-form name="radioButtonsFieldForm">
|
||||
|
||||
<ul class="unstyled">
|
||||
<li ng-repeat="item in vm.viewItems track by item.key">
|
||||
<umb-radiobutton name="{{model.alias}}" value="{{item.value}}" model="model.value" text="{{item.value}}" required="model.validation.mandatory && model.value == ''"></umb-radiobutton>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div ng-messages="radioButtonsFieldForm[model.alias].$error" show-validation-on-submit>
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function textAreaController($scope) {
|
||||
function textAreaController($scope, validationMessageService) {
|
||||
|
||||
// macro parameter editor doesn't contains a config object,
|
||||
// so we create a new one to hold any properties
|
||||
@@ -22,5 +22,11 @@ function textAreaController($scope) {
|
||||
}
|
||||
}
|
||||
$scope.model.change();
|
||||
|
||||
// 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.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function (value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.textAreaController", textAreaController);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<textarea ng-model="model.value" id="{{model.alias}}" name="textarea" rows="{{model.config.rows || 10}}" class="umb-property-editor umb-textarea textstring" val-server="value" ng-keyup="model.change()" ng-required="model.validation.mandatory" aria-required="{{model.validation.mandatory}}"></textarea>
|
||||
|
||||
<span ng-messages="textareaFieldForm.textarea.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="required">{{mandatoryMessage}}</span>
|
||||
<span class="help-inline" ng-message="valServer">{{textareaFieldForm.textarea.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
function textboxController($scope) {
|
||||
function textboxController($scope, validationMessageService) {
|
||||
// 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,11 @@ function textboxController($scope) {
|
||||
}
|
||||
}
|
||||
$scope.model.change();
|
||||
|
||||
|
||||
// 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.
|
||||
validationMessageService.getMandatoryMessage($scope.model.validation).then(function(value) {
|
||||
$scope.mandatoryMessage = value;
|
||||
});
|
||||
}
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.textboxController", textboxController);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div ng-messages="textboxFieldForm.textbox.$error" show-validation-on-submit>
|
||||
<p class="sr-only" ng-message="valServer" tabindex="0">{{model.label}} {{textboxFieldForm.textbox.errorMsg}}</p>
|
||||
<p class="help-inline" ng-message="valServer" tabindex="0" aria-hidden="true">{{textboxFieldForm.textbox.errorMsg}}</p>
|
||||
<p class="help-inline" ng-message="required"><localize key="general_required">Required</localize></p>
|
||||
<p class="help-inline" ng-message="required">{{mandatoryMessage}}</p>
|
||||
</div>
|
||||
|
||||
<div class="help" ng-if="model.count >= (model.config.maxChars*.8) && model.count <= model.config.maxChars">
|
||||
|
||||
@@ -1978,7 +1978,9 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="validateAsUrl">Validate as a URL</key>
|
||||
<key alias="enterCustomValidation">...or enter a custom validation</key>
|
||||
<key alias="fieldIsMandatory">Field is mandatory</key>
|
||||
<key alias="mandatoryMessage">Enter a custom validation error message (optional)</key>
|
||||
<key alias="validationRegExp">Enter a regular expression</key>
|
||||
<key alias="validationRegExpMessage">Enter a custom validation error message (optional)</key>
|
||||
<key alias="minCount">You need to add at least</key>
|
||||
<key alias="maxCount">You can only have</key>
|
||||
<key alias="items">items</key>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,10 @@ using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Editors.Filters
|
||||
@@ -43,8 +43,11 @@ namespace Umbraco.Web.Editors.Filters
|
||||
where TModelSave: IContentSave<TPersisted>
|
||||
where TModelWithProperties : IContentProperties<ContentPropertyBasic>
|
||||
{
|
||||
protected ContentModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, umbracoContextAccessor)
|
||||
private readonly ILocalizedTextService _textService;
|
||||
|
||||
protected ContentModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService) : base(logger, umbracoContextAccessor)
|
||||
{
|
||||
_textService = textService ?? throw new ArgumentNullException(nameof(textService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -122,6 +125,18 @@ namespace Umbraco.Web.Editors.Filters
|
||||
{
|
||||
var properties = modelWithProperties.Properties.ToDictionary(x => x.Alias, x => x);
|
||||
|
||||
// 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[]
|
||||
{
|
||||
_textService.Localize("validation", "invalidNull"),
|
||||
_textService.Localize("validation", "invalidEmpty")
|
||||
};
|
||||
var formatDefaultMessages = new[]
|
||||
{
|
||||
_textService.Localize("validation", "invalidPattern"),
|
||||
};
|
||||
|
||||
foreach (var p in dto.Properties)
|
||||
{
|
||||
var editor = p.PropertyEditor;
|
||||
@@ -141,7 +156,7 @@ namespace Umbraco.Web.Editors.Filters
|
||||
|
||||
var postedValue = postedProp.Value;
|
||||
|
||||
ValidatePropertyValue(model, modelWithProperties, editor, p, postedValue, modelState);
|
||||
ValidatePropertyValue(model, modelWithProperties, editor, p, postedValue, modelState, requiredDefaultMessages, formatDefaultMessages);
|
||||
|
||||
}
|
||||
|
||||
@@ -157,22 +172,34 @@ namespace Umbraco.Web.Editors.Filters
|
||||
/// <param name="property"></param>
|
||||
/// <param name="postedValue"></param>
|
||||
/// <param name="modelState"></param>
|
||||
/// <param name="requiredDefaultMessages"></param>
|
||||
/// <param name="formatDefaultMessages"></param>
|
||||
protected virtual void ValidatePropertyValue(
|
||||
TModelSave model,
|
||||
TModelWithProperties modelWithProperties,
|
||||
IDataEditor editor,
|
||||
ContentPropertyDto property,
|
||||
object postedValue,
|
||||
ModelStateDictionary modelState)
|
||||
ModelStateDictionary modelState,
|
||||
string[] requiredDefaultMessages,
|
||||
string[] formatDefaultMessages)
|
||||
{
|
||||
// validate
|
||||
var valueEditor = editor.GetValueEditor(property.DataType.Configuration);
|
||||
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, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
r.ErrorMessage = property.IsRequiredMessage;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(property.ValidationRegExp) && !string.IsNullOrWhiteSpace(property.ValidationRegExpMessage) && formatDefaultMessages.Contains(r.ErrorMessage, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
r.ErrorMessage = property.ValidationRegExpMessage;
|
||||
}
|
||||
|
||||
modelState.AddPropertyError(r, property.Alias, property.Culture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Web.Http.ModelBinding;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Editors.Filters
|
||||
@@ -12,7 +10,7 @@ namespace Umbraco.Web.Editors.Filters
|
||||
/// </summary>
|
||||
internal class ContentSaveModelValidator : ContentModelValidator<IContent, ContentItemSave, ContentVariantSave>
|
||||
{
|
||||
public ContentSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, umbracoContextAccessor)
|
||||
public ContentSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService) : base(logger, umbracoContextAccessor, textService)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,28 +23,30 @@ namespace Umbraco.Web.Editors.Filters
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
internal class MediaSaveModelValidator : ContentModelValidator<IMedia, MediaItemSave, IContentProperties<ContentPropertyBasic>>
|
||||
{
|
||||
public MediaSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor) : base(logger, umbracoContextAccessor)
|
||||
public MediaSaveModelValidator(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService) : base(logger, umbracoContextAccessor, textService)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -222,7 +222,9 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.DataTypeId = source.DataTypeId;
|
||||
target.DataTypeKey = source.DataTypeKey;
|
||||
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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -342,9 +342,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
|
||||
@@ -354,7 +364,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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user