diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs index 6ac936961f..e4a5b2e417 100644 --- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs @@ -454,10 +454,12 @@ namespace Umbraco.Web.Editors var validateAttempt = service.ValidateComposition(composition); if (validateAttempt == false) { - //if it's not successful then we need to return some model state for the property aliases that - // are duplicated - var invalidPropertyAliases = validateAttempt.Result.Distinct(); - AddCompositionValidationErrors(contentTypeSave, invalidPropertyAliases); + // if it's not successful then we need to return some model state for the property type and property group + // aliases that are duplicated + var invalidPropertyTypeAliases = validateAttempt.Result.Distinct(); + var invalidPropertyGroupAliases = (validateAttempt.Exception as InvalidCompositionException)?.PropertyGroupAliases ?? Array.Empty(); + + AddCompositionValidationErrors(contentTypeSave, invalidPropertyTypeAliases, invalidPropertyGroupAliases); var display = Mapper.Map(composition); //map the 'save' data on top @@ -472,22 +474,32 @@ namespace Umbraco.Web.Editors /// Adds errors to the model state if any invalid aliases are found then throws an error response if there are errors /// /// - /// + /// + /// /// - private void AddCompositionValidationErrors(TContentTypeSave contentTypeSave, IEnumerable invalidPropertyAliases) + private void AddCompositionValidationErrors(TContentTypeSave contentTypeSave, IEnumerable invalidPropertyTypeAliases, IEnumerable invalidPropertyGroupAliases) where TContentTypeSave : ContentTypeSave where TPropertyType : PropertyTypeBasic { - foreach (var propertyAlias in invalidPropertyAliases) + foreach (var propertyTypeAlias in invalidPropertyTypeAliases) { - // Find the property relating to these - var property = contentTypeSave.Groups.SelectMany(x => x.Properties).Single(x => x.Alias == propertyAlias); + // Find the property type relating to these + var property = contentTypeSave.Groups.SelectMany(x => x.Properties).Single(x => x.Alias == propertyTypeAlias); var group = contentTypeSave.Groups.Single(x => x.Properties.Contains(property)); var propertyIndex = group.Properties.IndexOf(property); var groupIndex = contentTypeSave.Groups.IndexOf(group); var key = $"Groups[{groupIndex}].Properties[{propertyIndex}].Alias"; - ModelState.AddModelError(key, "Duplicate property aliases not allowed between compositions"); + ModelState.AddModelError(key, "Duplicate property aliases are not allowed between compositions"); + } + + foreach (var propertyGroupAlias in invalidPropertyGroupAliases) + { + // Find the property group relating to these + var group = contentTypeSave.Groups.Single(x => x.Alias == propertyGroupAlias); + var groupIndex = contentTypeSave.Groups.IndexOf(group); + var key = $"Groups[{groupIndex}].Name"; + ModelState.AddModelError(key, "Duplicate property group aliases are not allowed between compositions"); } } @@ -519,7 +531,7 @@ namespace Umbraco.Web.Editors } if (invalidCompositionException != null) { - AddCompositionValidationErrors(contentTypeSave, invalidCompositionException.PropertyTypeAliases); + AddCompositionValidationErrors(contentTypeSave, invalidCompositionException.PropertyTypeAliases, invalidCompositionException.PropertyGroupAliases); return CreateModelStateValidationException(ctId, contentTypeSave, ct); } return null;