Finally, making some sense out of all this craziness

This commit is contained in:
Shannon
2020-06-23 13:34:19 +10:00
parent 5128084511
commit 80bbfaf7be
5 changed files with 115 additions and 60 deletions

View File

@@ -98,20 +98,22 @@ namespace Umbraco.Tests.Web.Validation
public void TestSerializer()
{
var nestedLevel2 = new NestedValidationResults();
nestedLevel2.AddElementTypeValidationResults(
new ValidationResultCollection(
new ValidationResult("error2-1", new[] { "level2" }),
new ValidationResult("error2-2", new[] { "level2" })));
var elementTypeResult2 = new ElementTypeValidationResult("type2");
var propertyTypeResult2 = new PropertyTypeValidationResult("prop2");
propertyTypeResult2.ValidationResults.Add(new ValidationResult("error2-1", new[] { "level2" }));
propertyTypeResult2.ValidationResults.Add(new ValidationResult("error2-2", new[] { "level2" }));
elementTypeResult2.ValidationResults.Add(propertyTypeResult2);
nestedLevel2.ValidationResults.Add(elementTypeResult2);
var nestedLevel1 = new NestedValidationResults();
nestedLevel1.AddElementTypeValidationResults(
new ValidationResultCollection(
new ValidationResult("error1-1", new[] { "level1" }),
nestedLevel2));
var elementTypeResult1 = new ElementTypeValidationResult("type1");
var propertyTypeResult1 = new PropertyTypeValidationResult("prop1");
propertyTypeResult1.ValidationResults.Add(new ValidationResult("error1-1", new[] { "level1" }));
propertyTypeResult1.ValidationResults.Add(nestedLevel2); // This is a nested result within the level 1
elementTypeResult1.ValidationResults.Add(propertyTypeResult1);
nestedLevel1.ValidationResults.Add(elementTypeResult1);
var propValidationResult = new PropertyValidationResult(nestedLevel1);
var serialized = JsonConvert.SerializeObject(propValidationResult, Formatting.Indented, new ValidationResultConverter());
var serialized = JsonConvert.SerializeObject(nestedLevel1, Formatting.Indented, new ValidationResultConverter());
Console.WriteLine(serialized);
}
@@ -125,36 +127,26 @@ namespace Umbraco.Tests.Web.Validation
var content = MockedContent.CreateTextpageContent(_contentType, "test", -1);
// TODO: Ok now test with a 3rd/4th level complex nested editor
// const string complexValue = @"[{
// ""key"": ""c8df5136-d606-41f0-9134-dea6ae0c2fd9"",
// ""name"": ""Hello world"",
// ""ncContentTypeAlias"": """ + ContentTypeAlias + @""",
// ""title"": ""Hello world""
// }, {
// ""key"": ""f916104a-4082-48b2-a515-5c4bf2230f38"",
// ""name"": ""Super nested"",
// ""ncContentTypeAlias"": """ + ContentTypeAlias + @""",
// ""title"": ""Hi there!""
// }
//]";
// TODO: Ok now test with a 4th level complex nested editor
const string complexValue = @"[{
""key"": ""c8df5136-d606-41f0-9134-dea6ae0c2fd9"",
""name"": ""Hello world"",
""ncContentTypeAlias"": """ + ContentTypeAlias + @""",
""title"": ""Hello world""
""title"": ""Hello world"",
""bodyText"": ""The world is round""
}, {
""key"": ""f916104a-4082-48b2-a515-5c4bf2230f38"",
""name"": ""Super nested"",
""ncContentTypeAlias"": """ + ContentTypeAlias + @""",
""title"": ""Hi there!"",
""bodyText"": ""Well hello there"",
""complex"" : [{
""key"": ""77E15DE9-1C79-47B2-BC60-4913BC4D4C6A"",
""name"": ""I am a sub nested content"",
""ncContentTypeAlias"": """ + ContentTypeAlias + @""",
""title"": ""Hello up there :)""
""title"": ""Hello up there :)"",
""bodyText"": ""Hello way up there on a different level""
}]
}
]";
@@ -234,19 +226,50 @@ namespace Umbraco.Tests.Web.Validation
var jsonNestedError = JsonConvert.DeserializeObject<JObject>(nestedError.ErrorMessage);
Assert.AreEqual(JTokenType.Array, jsonNestedError["nestedValidation"].Type);
var nestedValidation = (JArray)jsonNestedError["nestedValidation"];
Assert.AreEqual(2, nestedValidation.Count); // there are 2 because there are 2 nested content rows
AssertNestedValidation(nestedValidation, 2); // there are 2 because there are 2 nested content rows
}
private void AssertNestedValidation(JArray nestedValidation, int rows)
{
Assert.AreEqual(rows, nestedValidation.Count);
foreach (var rowErrors in nestedValidation)
{
var elementTypeErrors = (JArray)rowErrors; // this is an array of errors for the nested content row (element type)
Assert.AreEqual(2, elementTypeErrors.Count);
foreach (var elementTypeErr in elementTypeErrors)
Assert.AreEqual(JTokenType.Object, rowErrors.Type);
var elementTypeErrors = (JObject)rowErrors; // this is a dictionary of element type alias -> dictionary of errors -> prop alias -> array errors
Assert.AreEqual(1, elementTypeErrors.Count); // there is 1 element type in error
foreach (var elementTypeAliasToErrors in elementTypeErrors)
{
Assert.IsNotEmpty(elementTypeErr["errorMessage"].Value<string>());
Assert.AreEqual(1, elementTypeErr["memberNames"].Value<JArray>().Count);
Assert.AreEqual("textPage", elementTypeAliasToErrors.Key);
var propErrors = (JObject)elementTypeAliasToErrors.Value;
foreach (var propAliasToErrors in propErrors)
{
Assert.AreEqual(JTokenType.Array, propAliasToErrors.Value.Type);
var propTypeErrors = (JArray)propAliasToErrors.Value;
foreach (var propError in propTypeErrors)
{
var nested = propError["nestedValidation"];
if (nested != null)
{
// recurse
AssertNestedValidation((JArray)nested, 1); // we know this is 1 row
continue;
}
Assert.IsNotEmpty(propError["errorMessage"].Value<string>());
Assert.AreEqual(1, propError["memberNames"].Value<JArray>().Count);
}
}
}
}
}
[HideFromTypeFinder]
[DataEditor("complexTest", "test", "test")]
public class ComplexTestEditor : NestedContentPropertyEditor

View File

@@ -39,7 +39,7 @@ namespace Umbraco.Web.PropertyEditors
var result = new NestedValidationResults();
foreach(var rowResult in rowResults)
{
result.AddElementTypeValidationResults(rowResult);
result.ValidationResults.Add(rowResult);
}
return result.Yield();
}
@@ -55,30 +55,36 @@ namespace Umbraco.Web.PropertyEditors
/// </summary>
/// <param name="rawValue"></param>
/// <returns></returns>
protected IEnumerable<ValidationResultCollection> GetNestedValidationResults(IEnumerable<ElementTypeValidationModel> elements)
protected IEnumerable<ElementTypeValidationResult> GetNestedValidationResults(IEnumerable<ElementTypeValidationModel> elements)
{
foreach (var row in elements)
{
var nestedValidation = new List<ValidationResult>();
var elementTypeValidationResult = new ElementTypeValidationResult(row.ElementTypeAlias);
foreach (var prop in row.PropertyTypeValidation)
{
var propValidationResult = new PropertyTypeValidationResult(prop.PropertyType.Alias);
foreach (var validationResult in _propertyValidationService.ValidatePropertyValue(prop.PropertyType, prop.PostedValue))
{
nestedValidation.Add(validationResult);
// add the result to the property results
propValidationResult.ValidationResults.Add(validationResult);
}
// add the property results to the element type results
elementTypeValidationResult.ValidationResults.Add(propValidationResult);
}
if (nestedValidation.Count > 0)
if (elementTypeValidationResult.ValidationResults.Count > 0)
{
yield return new ValidationResultCollection(nestedValidation.ToArray());
yield return elementTypeValidationResult;
}
}
}
public class PropertyTypeValidationModel
{
public PropertyTypeValidationModel(object postedValue, PropertyType propertyType)
public PropertyTypeValidationModel(PropertyType propertyType, object postedValue)
{
PostedValue = postedValue ?? throw new ArgumentNullException(nameof(postedValue));
PropertyType = propertyType ?? throw new ArgumentNullException(nameof(propertyType));
@@ -90,9 +96,17 @@ namespace Umbraco.Web.PropertyEditors
public class ElementTypeValidationModel
{
public ElementTypeValidationModel(string elementTypeAlias)
{
ElementTypeAlias = elementTypeAlias;
}
private List<PropertyTypeValidationModel> _list = new List<PropertyTypeValidationModel>();
public IEnumerable<PropertyTypeValidationModel> PropertyTypeValidation => _list;
public string ElementTypeAlias { get; }
public void AddPropertyTypeValidation(PropertyTypeValidationModel propValidation) => _list.Add(propValidation);
}
}

View File

@@ -269,10 +269,11 @@ namespace Umbraco.Web.PropertyEditors
{
foreach (var row in _nestedContentValues.GetPropertyValues(value))
{
var elementValidation = new ElementTypeValidationModel();
var elementValidation = new ElementTypeValidationModel(row.ContentTypeAlias);
foreach (var prop in row.PropertyValues)
{
elementValidation.AddPropertyTypeValidation(new PropertyTypeValidationModel(prop.Value.Value, prop.Value.PropertyType));
elementValidation.AddPropertyTypeValidation(
new PropertyTypeValidationModel(prop.Value.PropertyType, prop.Value.Value));
}
yield return elementValidation;
}

View File

@@ -3,15 +3,28 @@ using System.ComponentModel.DataAnnotations;
namespace Umbraco.Web.PropertyEditors.Validation
{
public class ValidationResultCollection : ValidationResult
public class PropertyTypeValidationResult : ValidationResult
{
public ValidationResultCollection(params ValidationResult[] nested)
public PropertyTypeValidationResult(string propertyTypeAlias)
: base(string.Empty)
{
ValidationResults = new List<ValidationResult>(nested);
PropertyTypeAlias = propertyTypeAlias;
}
public IList<ValidationResult> ValidationResults { get; }
public IList<ValidationResult> ValidationResults { get; } = new List<ValidationResult>();
public string PropertyTypeAlias { get; }
}
public class ElementTypeValidationResult : ValidationResult
{
public ElementTypeValidationResult(string elementTypeAlias)
: base(string.Empty)
{
ElementTypeAlias = elementTypeAlias;
}
public IList<PropertyTypeValidationResult> ValidationResults { get; } = new List<PropertyTypeValidationResult>();
public string ElementTypeAlias { get; }
}
/// <summary>
@@ -27,11 +40,6 @@ namespace Umbraco.Web.PropertyEditors.Validation
{
}
public void AddElementTypeValidationResults(ValidationResultCollection resultCollection)
{
ValidationResults.Add(resultCollection);
}
public IList<ValidationResultCollection> ValidationResults { get; } = new List<ValidationResultCollection>();
public IList<ElementTypeValidationResult> ValidationResults { get; } = new List<ElementTypeValidationResult>();
}
}

View File

@@ -42,16 +42,25 @@ namespace Umbraco.Web.PropertyEditors.Validation
jo.Add("nestedValidation", obj);
jo.WriteTo(writer);
}
else if (validationResult is ValidationResultCollection resultCollection && resultCollection.ValidationResults.Count > 0)
else if (validationResult is ElementTypeValidationResult elementTypeValidationResult && elementTypeValidationResult.ValidationResults.Count > 0)
{
var ja = new JArray();
foreach (var result in resultCollection.ValidationResults)
{
// recurse to write out the ValidationResult
var obj = JObject.FromObject(result, camelCaseSerializer);
ja.Add(obj);
var joElementType = new JObject();
var joPropertyType = new JObject();
// loop over property validations
foreach (var propTypeResult in elementTypeValidationResult.ValidationResults)
{
var ja = new JArray();
foreach (var result in propTypeResult.ValidationResults)
{
// recurse to get the validation result object and add to the array
var obj = JObject.FromObject(result, camelCaseSerializer);
ja.Add(obj);
}
// create a dictionary entry
joPropertyType.Add(propTypeResult.PropertyTypeAlias, ja);
}
ja.WriteTo(writer);
joElementType.Add(elementTypeValidationResult.ElementTypeAlias, joPropertyType);
joElementType.WriteTo(writer);
}
else
{