diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 142d7540c2..f5a38a96cb 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -275,6 +275,19 @@ namespace Umbraco.Core.Models if (ValidateAll().Any()) return false; + // Name and PublishName are managed by the repository, but Names and PublishNames + // must be managed here as they depend on the existing / supported variations. + if (string.IsNullOrWhiteSpace(Name)) + throw new InvalidOperationException($"Cannot publish invariant culture without a name."); + PublishName = Name; + foreach (var (languageId, name) in Names) + { + if (string.IsNullOrWhiteSpace(name)) + throw new InvalidOperationException($"Cannot publish {languageId} culture without a name."); + SetPublishName(languageId, name); + } + + // property.PublishAllValues only deals with supported variations (if any) foreach (var property in Properties) property.PublishAllValues(); @@ -298,15 +311,21 @@ namespace Umbraco.Core.Models // the values we want to publish should be valid if (Validate(languageId, segment).Any()) return false; + + // Name and PublishName are managed by the repository, but Names and PublishNames + // must be managed here as they depend on the existing / supported variations. + if (segment == null) + { + var name = GetName(languageId); + if (string.IsNullOrWhiteSpace(name)) + throw new InvalidOperationException($"Cannot publish {languageId?.ToString() ?? "invariant"} culture without a name."); + SetPublishName(languageId, name); + } // property.PublishValue throws on invalid variation, so filter them out foreach (var property in Properties.Where(x => x.PropertyType.ValidateVariation(languageId, segment, throwIfInvalid: false))) property.PublishValue(languageId, segment); - // Name and PublishName are managed by the repository, but Names and PublishNames - // must be managed here as they depend on the existing / supported variations. - SetPublishName(languageId, GetName(languageId)); - _publishedState = PublishedState.Publishing; return true; } @@ -317,15 +336,18 @@ namespace Umbraco.Core.Models // the values we want to publish should be valid if (ValidateCulture(languageId).Any()) return false; + + // Name and PublishName are managed by the repository, but Names and PublishNames + // must be managed here as they depend on the existing / supported variations. + var name = GetName(languageId); + if (string.IsNullOrWhiteSpace(name)) + throw new InvalidOperationException($"Cannot publish {languageId?.ToString() ?? "invariant"} culture without a name."); + SetPublishName(languageId, name); // property.PublishCultureValues only deals with supported variations (if any) foreach (var property in Properties) property.PublishCultureValues(languageId); - // Name and PublishName are managed by the repository, but Names and PublishNames - // must be managed here as they depend on the existing / supported variations. - SetPublishName(languageId, GetName(languageId)); - _publishedState = PublishedState.Publishing; return true; } diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index 8965d60018..6fba071709 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -286,7 +286,7 @@ AnotherContentFinder public void GetDataEditors() { var types = _typeLoader.GetDataEditors(); - Assert.AreEqual(42, types.Count()); + Assert.AreEqual(43, types.Count()); } [Test] diff --git a/src/Umbraco.Tests/Models/VariationTests.cs b/src/Umbraco.Tests/Models/VariationTests.cs index 3b293621d5..d0af5ee2a4 100644 --- a/src/Umbraco.Tests/Models/VariationTests.cs +++ b/src/Umbraco.Tests/Models/VariationTests.cs @@ -236,6 +236,8 @@ namespace Umbraco.Tests.Models // can publish value // and get edited and published values + Assert.Throws(() => content.PublishValues(1)); // no name + content.SetName(1, "name-fr"); content.PublishValues(1); Assert.AreEqual("b", content.GetValue("prop")); Assert.IsNull(content.GetValue("prop", published: true)); diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs index 72842c5354..83345988be 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeProfileExtensions.cs @@ -163,7 +163,7 @@ namespace Umbraco.Web.Models.Mapping // fixme not so clean really var isPublishing = typeof(IContentType).IsAssignableFrom(typeof(TDestination)); - return mapping + mapping = mapping //only map id if set to something higher then zero .ForMember(dest => dest.Id, opt => opt.Condition(src => (Convert.ToInt32(src.Id) > 0))) .ForMember(dest => dest.Id, opt => opt.MapFrom(src => Convert.ToInt32(src.Id))) @@ -179,10 +179,15 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dest => dest.PropertyGroups, opt => opt.Ignore()) .ForMember(dest => dest.NoGroupPropertyTypes, opt => opt.Ignore()) // ignore, composition is managed in AfterMapContentTypeSaveToEntity - .ForMember(dest => dest.ContentTypeComposition, opt => opt.Ignore()) + .ForMember(dest => dest.ContentTypeComposition, opt => opt.Ignore()); - .ForMember(dto => dto.Variations, opt => opt.ResolveUsing>()) + // ignore for members + mapping = typeof(TDestination) == typeof(IMemberType) + ? mapping.ForMember(dto => dto.Variations, opt => opt.Ignore()) + : mapping.ForMember(dto => dto.Variations, opt => opt.ResolveUsing>()); + + mapping = mapping .ForMember( dest => dest.AllowedContentTypes, opt => opt.MapFrom(src => src.AllowedContentTypes.Select((t, i) => new ContentTypeSort(t, i)))) @@ -257,6 +262,8 @@ namespace Umbraco.Web.Models.Mapping // because all property collections were rebuilt, there is no need to remove // some old properties, they are just gone and will be cleared by the repository }); + + return mapping; } private static PropertyGroup MapSaveGroup(PropertyGroupBasic sourceGroup, IEnumerable destOrigGroups)