WIP - Fixing up validation so that invariant properties are only validated on the default lang or if the item is not published
This commit is contained in:
@@ -1,11 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -173,18 +169,21 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="culture"></param>
|
||||
/// <returns>A value indicating whether it was possible to publish the names and values for the specified
|
||||
/// culture(s). The method may fail if required names are not set, but it does NOT validate property data</returns>
|
||||
public static bool PublishCulture(this IContent content, string culture = "*")
|
||||
public static bool PublishCulture(this IContent content, CultureType culture = null)
|
||||
{
|
||||
culture = culture.NullOrWhiteSpaceAsNull();
|
||||
culture = culture ?? CultureType.All;
|
||||
|
||||
// the variation should be supported by the content type properties
|
||||
// if the content type is invariant, only '*' and 'null' is ok
|
||||
// if the content type varies, everything is ok because some properties may be invariant
|
||||
if (!content.ContentType.SupportsPropertyVariation(culture, "*", true))
|
||||
if (!content.ContentType.SupportsPropertyVariation(culture.Culture, "*", true))
|
||||
throw new NotSupportedException($"Culture \"{culture}\" is not supported by content type \"{content.ContentType.Alias}\" with variation \"{content.ContentType.Variations}\".");
|
||||
|
||||
var alsoInvariant = false;
|
||||
if (culture == "*") // all cultures
|
||||
|
||||
switch (culture.CultureBehavior)
|
||||
{
|
||||
case CultureType.Behavior.All:
|
||||
{
|
||||
foreach (var c in content.AvailableCultures)
|
||||
{
|
||||
@@ -193,26 +192,32 @@ namespace Umbraco.Core.Models
|
||||
return false;
|
||||
content.SetPublishInfo(c, name, DateTime.Now);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (culture == null) // invariant culture
|
||||
case CultureType.Behavior.Invariant:
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(content.Name))
|
||||
return false;
|
||||
// PublishName set by repository - nothing to do here
|
||||
break;
|
||||
}
|
||||
else // one single culture
|
||||
case CultureType.Behavior.Explicit:
|
||||
{
|
||||
var name = content.GetCultureName(culture);
|
||||
var name = content.GetCultureName(culture.Culture);
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return false;
|
||||
content.SetPublishInfo(culture, name, DateTime.Now);
|
||||
alsoInvariant = true; // we also want to publish invariant values
|
||||
content.SetPublishInfo(culture.Culture, name, DateTime.Now);
|
||||
alsoInvariant = culture.IsDefaultCulture; // we also want to publish invariant values
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
// property.PublishValues only publishes what is valid, variation-wise
|
||||
foreach (var property in content.Properties)
|
||||
{
|
||||
property.PublishValues(culture);
|
||||
property.PublishValues(culture.Culture);
|
||||
if (alsoInvariant)
|
||||
property.PublishValues(null);
|
||||
}
|
||||
|
||||
46
src/Umbraco.Core/Models/CultureType.cs
Normal file
46
src/Umbraco.Core/Models/CultureType.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="CultureType"/> represents either All cultures, a Single culture or the Invariant culture
|
||||
/// </summary>
|
||||
internal class CultureType
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents All cultures
|
||||
/// </summary>
|
||||
public static CultureType All { get; } = new CultureType("*");
|
||||
|
||||
/// <summary>
|
||||
/// Represents the Invariant culture
|
||||
/// </summary>
|
||||
public static CultureType Invariant { get; } = new CultureType(null);
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Single culture
|
||||
/// </summary>
|
||||
/// <param name="culture"></param>
|
||||
/// <param name="isDefault"></param>
|
||||
/// <returns></returns>
|
||||
public static CultureType Single(string culture, bool isDefault)
|
||||
{
|
||||
return new CultureType(culture, isDefault);
|
||||
}
|
||||
|
||||
private CultureType(string culture, bool isDefault = false)
|
||||
{
|
||||
Culture = culture;
|
||||
IsDefaultCulture = isDefault;
|
||||
}
|
||||
|
||||
public string Culture { get; }
|
||||
public Behavior CultureBehavior => Culture == "*" ? Behavior.All : Culture == null ? Behavior.Invariant : Behavior.Explicit;
|
||||
public bool IsDefaultCulture { get; }
|
||||
|
||||
public enum Behavior
|
||||
{
|
||||
All,
|
||||
Invariant,
|
||||
Explicit
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
internal static class LanguageRepositoryExtensions
|
||||
{
|
||||
public static bool IsDefault(this ILanguageRepository repo, string culture)
|
||||
{
|
||||
return repo.GetDefaultIsoCode().InvariantEquals(culture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services.Changes;
|
||||
@@ -886,12 +887,13 @@ namespace Umbraco.Core.Services.Implement
|
||||
if (!culture.IsNullOrWhiteSpace() && culture != "*")
|
||||
{
|
||||
// publish the invariant values
|
||||
// fixme: really? shouldn't we only publish invariant values if the culture is the default?
|
||||
var publishInvariant = content.PublishCulture(null);
|
||||
if (!publishInvariant)
|
||||
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content);
|
||||
|
||||
//validate the property values
|
||||
if (!_propertyValidationService.Value.IsPropertyDataValid(content, out invalidProperties))
|
||||
if (!_propertyValidationService.Value.IsPropertyDataValid(content, out invalidProperties, CultureType.Single(culture, _languageRepository.IsDefault(culture))))
|
||||
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content)
|
||||
{
|
||||
InvalidProperties = invalidProperties
|
||||
@@ -899,12 +901,12 @@ namespace Umbraco.Core.Services.Implement
|
||||
}
|
||||
|
||||
// publish the culture(s)
|
||||
var publishCulture = content.PublishCulture(culture);
|
||||
var publishCulture = content.PublishCulture(CultureType.All);
|
||||
if (!publishCulture)
|
||||
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content);
|
||||
|
||||
//validate the property values
|
||||
if (!_propertyValidationService.Value.IsPropertyDataValid(content, out invalidProperties))
|
||||
if (!_propertyValidationService.Value.IsPropertyDataValid(content, out invalidProperties, CultureType.All))
|
||||
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content)
|
||||
{
|
||||
InvalidProperties = invalidProperties
|
||||
@@ -941,14 +943,17 @@ namespace Umbraco.Core.Services.Implement
|
||||
: new PublishResult(PublishResultType.FailedPublishNothingToPublish, evtMsgs, content);
|
||||
}
|
||||
|
||||
//fixme: Shouldn't we makes ure that all string cultures here are valid? i.e. no * or null is allowed when using this method
|
||||
|
||||
if (cultures.Select(content.PublishCulture).Any(isValid => !isValid))
|
||||
var cultureTypes = cultures.ToDictionary(x => x, x => CultureType.Single(x, _languageRepository.IsDefault(x)));
|
||||
|
||||
if (cultureTypes.Select(x => content.PublishCulture(x.Value)).Any(isValid => !isValid))
|
||||
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content);
|
||||
|
||||
//validate the property values on the cultures trying to be published
|
||||
foreach (var culture in cultures)
|
||||
foreach (var culture in cultureTypes)
|
||||
{
|
||||
if (!_propertyValidationService.Value.IsPropertyDataValid(content, out var invalidProperties, culture))
|
||||
if (!_propertyValidationService.Value.IsPropertyDataValid(content, out var invalidProperties, culture.Value))
|
||||
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content)
|
||||
{
|
||||
InvalidProperties = invalidProperties
|
||||
@@ -1333,7 +1338,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
//publish the culture values and validate the property values, if validation fails, log the invalid properties so the develeper has an idea of what has failed
|
||||
Property[] invalidProperties = null;
|
||||
var tryPublish = d.PublishCulture(culture) && _propertyValidationService.Value.IsPropertyDataValid(d, out invalidProperties);
|
||||
var cultureType = CultureType.Single(culture, _languageRepository.IsDefault(culture));
|
||||
var tryPublish = d.PublishCulture(cultureType) && _propertyValidationService.Value.IsPropertyDataValid(d, out invalidProperties, cultureType);
|
||||
if (invalidProperties != null && invalidProperties.Length > 0)
|
||||
Logger.Warn<ContentService>("Scheduled publishing will fail for document {DocumentId} and culture {Culture} because of invalid properties {InvalidProperties}",
|
||||
d.Id, culture, string.Join(",", invalidProperties.Select(x => x.Alias)));
|
||||
@@ -1429,9 +1435,16 @@ namespace Umbraco.Core.Services.Implement
|
||||
|
||||
// variant content type - publish specified cultures
|
||||
// invariant content type - publish only the invariant culture
|
||||
return content.ContentType.VariesByCulture()
|
||||
? culturesToPublish.All(culture => content.PublishCulture(culture) && _propertyValidationService.Value.IsPropertyDataValid(content, out _))
|
||||
: content.PublishCulture() && _propertyValidationService.Value.IsPropertyDataValid(content, out _);
|
||||
if (content.ContentType.VariesByCulture())
|
||||
{
|
||||
return culturesToPublish.All(culture =>
|
||||
{
|
||||
var cultureType = CultureType.Single(culture, _languageRepository.IsDefault(culture));
|
||||
return content.PublishCulture(cultureType) && _propertyValidationService.Value.IsPropertyDataValid(content, out _, cultureType);
|
||||
});
|
||||
}
|
||||
|
||||
return content.PublishCulture(CultureType.Invariant) && _propertyValidationService.Value.IsPropertyDataValid(content, out _, CultureType.Invariant);
|
||||
}
|
||||
|
||||
// utility 'ShouldPublish' func used by SaveAndPublishBranch
|
||||
|
||||
@@ -31,9 +31,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Validates the content item's properties pass validation rules
|
||||
/// </summary>
|
||||
/// <para>If the content type is variant, then culture can be either '*' or an actual culture, but neither 'null' nor
|
||||
/// 'empty'. If the content type is invariant, then culture can be either '*' or null or empty.</para>
|
||||
public bool IsPropertyDataValid(IContentBase content, out Property[] invalidProperties, string culture = "*")
|
||||
public bool IsPropertyDataValid(IContent content, out Property[] invalidProperties, CultureType culture)
|
||||
{
|
||||
// select invalid properties
|
||||
invalidProperties = content.Properties.Where(x =>
|
||||
@@ -44,17 +42,35 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var varies = x.PropertyType.VariesByCulture();
|
||||
|
||||
if (culture == null)
|
||||
switch (culture.CultureBehavior)
|
||||
{
|
||||
case CultureType.Behavior.Invariant:
|
||||
return !(varies || IsPropertyValid(x, null)); // validate invariant property, invariant culture
|
||||
case CultureType.Behavior.All:
|
||||
return !IsPropertyValid(x, culture.Culture); // validate property, all cultures
|
||||
case CultureType.Behavior.Explicit:
|
||||
if (varies)
|
||||
{
|
||||
return !IsPropertyValid(x, culture.Culture); // validate variant property, explicit culture
|
||||
}
|
||||
else
|
||||
{
|
||||
//We only want to validate the invariant property against an explicit culture if:
|
||||
// * The culture is the default OR
|
||||
// * The content item isn't published
|
||||
|
||||
if (culture == "*")
|
||||
return !IsPropertyValid(x, culture); // validate property, all cultures
|
||||
//This is because an invariant property is only edited on the default culture, but if the
|
||||
//content item isn't published, we can't allow publishing of the specific non default culture
|
||||
//if the invariant property data is invalid.
|
||||
|
||||
return varies
|
||||
? !IsPropertyValid(x, culture) // validate variant property, explicit culture
|
||||
: !IsPropertyValid(x, null); // validate invariant property, explicit culture
|
||||
})
|
||||
.ToArray();
|
||||
return (culture.IsDefaultCulture || !content.Published)
|
||||
&& !IsPropertyValid(x, null); // validate invariant property, explicit culture
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
}).ToArray();
|
||||
|
||||
return invalidProperties.Length == 0;
|
||||
}
|
||||
|
||||
@@ -209,7 +209,9 @@
|
||||
<Compile Include="IO\MediaPathSchemes\UniqueMediaPathScheme.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_1\ChangeNuCacheJsonFormat.cs" />
|
||||
<Compile Include="Models\CultureType.cs" />
|
||||
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\LanguageRepositoryExtensions.cs" />
|
||||
<Compile Include="PropertyEditors\DateTimeConfiguration.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameLabelAndRichTextPropertyEditorAliases.cs" />
|
||||
<Compile Include="PublishedModelFactoryExtensions.cs" />
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
Thread.Sleep(500); //The "Date" wont be dirty if the test runs too fast since it will be the same date
|
||||
content.SetCultureName("name-fr", langFr);
|
||||
content.PublishCulture(langFr); //we've set the name, now we're publishing it
|
||||
content.PublishCulture(CultureType.Single(langFr, false)); //we've set the name, now we're publishing it
|
||||
Assert.IsTrue(content.IsPropertyDirty("PublishCultureInfos")); //now it will be changed since the collection has changed
|
||||
var frCultureName = content.PublishCultureInfos[langFr];
|
||||
Assert.IsTrue(frCultureName.IsPropertyDirty("Date"));
|
||||
@@ -116,7 +116,7 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
Thread.Sleep(500); //The "Date" wont be dirty if the test runs too fast since it will be the same date
|
||||
content.SetCultureName("name-fr", langFr);
|
||||
content.PublishCulture(langFr); //we've set the name, now we're publishing it
|
||||
content.PublishCulture(CultureType.Single(langFr, false)); //we've set the name, now we're publishing it
|
||||
Assert.IsTrue(frCultureName.IsPropertyDirty("Date"));
|
||||
Assert.IsTrue(content.IsPropertyDirty("PublishCultureInfos")); //it's true now since we've updated a name
|
||||
}
|
||||
@@ -303,7 +303,7 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
content.SetCultureName("Hello", "en-US");
|
||||
content.SetCultureName("World", "es-ES");
|
||||
content.PublishCulture("en-US");
|
||||
content.PublishCulture(CultureType.All);
|
||||
|
||||
// should not try to clone something that's not Published or Unpublished
|
||||
// (and in fact it will not work)
|
||||
@@ -414,7 +414,7 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
content.SetCultureName("Hello", "en-US");
|
||||
content.SetCultureName("World", "es-ES");
|
||||
content.PublishCulture("en-US");
|
||||
content.PublishCulture(CultureType.All);
|
||||
|
||||
var i = 200;
|
||||
foreach (var property in content.Properties)
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
// can publish value
|
||||
// and get edited and published values
|
||||
Assert.IsTrue(content.PublishCulture());
|
||||
Assert.IsTrue(content.PublishCulture(CultureType.Invariant));
|
||||
Assert.AreEqual("a", content.GetValue("prop"));
|
||||
Assert.AreEqual("a", content.GetValue("prop", published: true));
|
||||
|
||||
@@ -305,9 +305,9 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
// can publish value
|
||||
// and get edited and published values
|
||||
Assert.IsFalse(content.PublishCulture(langFr)); // no name
|
||||
Assert.IsFalse(content.PublishCulture(CultureType.Single(langFr, false))); // no name
|
||||
content.SetCultureName("name-fr", langFr);
|
||||
Assert.IsTrue(content.PublishCulture(langFr));
|
||||
Assert.IsTrue(content.PublishCulture(CultureType.Single(langFr, false)));
|
||||
Assert.IsNull(content.GetValue("prop"));
|
||||
Assert.IsNull(content.GetValue("prop", published: true));
|
||||
Assert.AreEqual("c", content.GetValue("prop", langFr));
|
||||
@@ -321,7 +321,7 @@ namespace Umbraco.Tests.Models
|
||||
Assert.IsNull(content.GetValue("prop", langFr, published: true));
|
||||
|
||||
// can publish all
|
||||
Assert.IsTrue(content.PublishCulture("*"));
|
||||
Assert.IsTrue(content.PublishCulture(CultureType.All));
|
||||
Assert.IsNull(content.GetValue("prop"));
|
||||
Assert.IsNull(content.GetValue("prop", published: true));
|
||||
Assert.AreEqual("c", content.GetValue("prop", langFr));
|
||||
@@ -331,14 +331,14 @@ namespace Umbraco.Tests.Models
|
||||
content.UnpublishCulture(langFr);
|
||||
Assert.AreEqual("c", content.GetValue("prop", langFr));
|
||||
Assert.IsNull(content.GetValue("prop", langFr, published: true));
|
||||
content.PublishCulture(langFr);
|
||||
content.PublishCulture(CultureType.Single(langFr, false));
|
||||
Assert.AreEqual("c", content.GetValue("prop", langFr));
|
||||
Assert.AreEqual("c", content.GetValue("prop", langFr, published: true));
|
||||
|
||||
content.UnpublishCulture(); // clears invariant props if any
|
||||
Assert.IsNull(content.GetValue("prop"));
|
||||
Assert.IsNull(content.GetValue("prop", published: true));
|
||||
content.PublishCulture(); // publishes invariant props if any
|
||||
content.PublishCulture(CultureType.Invariant); // publishes invariant props if any
|
||||
Assert.IsNull(content.GetValue("prop"));
|
||||
Assert.IsNull(content.GetValue("prop", published: true));
|
||||
|
||||
@@ -384,15 +384,19 @@ namespace Umbraco.Tests.Models
|
||||
|
||||
content.SetCultureName("hello", langFr);
|
||||
|
||||
Assert.IsTrue(content.PublishCulture(langFr)); // succeeds because names are ok (not validating properties here)
|
||||
Assert.IsFalse(propertyValidationService.IsPropertyDataValid(content, out _, langFr));// fails because prop1 is mandatory
|
||||
var langFrCultureType = CultureType.Single(langFr, false);
|
||||
|
||||
Assert.IsTrue(content.PublishCulture(CultureType.Single(langFr, false))); // succeeds because names are ok (not validating properties here)
|
||||
Assert.IsFalse(propertyValidationService.IsPropertyDataValid(content, out _, langFrCultureType));// fails because prop1 is mandatory
|
||||
|
||||
content.SetValue("prop1", "a", langFr);
|
||||
Assert.IsTrue(content.PublishCulture(langFr)); // succeeds because names are ok (not validating properties here)
|
||||
Assert.IsFalse(propertyValidationService.IsPropertyDataValid(content, out _, langFr));// fails because prop2 is mandatory and invariant
|
||||
Assert.IsTrue(content.PublishCulture(CultureType.Single(langFr, false))); // succeeds because names are ok (not validating properties here)
|
||||
// fails because prop2 is mandatory and invariant and the item isn't published.
|
||||
// Invariant is validated against the default language except when there isn't a published version, in that case it's always validated.
|
||||
Assert.IsFalse(propertyValidationService.IsPropertyDataValid(content, out _, langFrCultureType));
|
||||
content.SetValue("prop2", "x");
|
||||
Assert.IsTrue(content.PublishCulture(langFr)); // still ok...
|
||||
Assert.IsTrue(propertyValidationService.IsPropertyDataValid(content, out _, langFr));// now it's ok
|
||||
Assert.IsTrue(content.PublishCulture(CultureType.Single(langFr, false))); // still ok...
|
||||
Assert.IsTrue(propertyValidationService.IsPropertyDataValid(content, out _, langFrCultureType));// now it's ok
|
||||
|
||||
Assert.AreEqual("a", content.GetValue("prop1", langFr, published: true));
|
||||
Assert.AreEqual("x", content.GetValue("prop2", published: true));
|
||||
@@ -423,12 +427,12 @@ namespace Umbraco.Tests.Models
|
||||
content.SetValue("prop", "a-es", langEs);
|
||||
|
||||
// cannot publish without a name
|
||||
Assert.IsFalse(content.PublishCulture(langFr));
|
||||
Assert.IsFalse(content.PublishCulture(CultureType.Single(langFr, false)));
|
||||
|
||||
// works with a name
|
||||
// and then FR is available, and published
|
||||
content.SetCultureName("name-fr", langFr);
|
||||
Assert.IsTrue(content.PublishCulture(langFr));
|
||||
Assert.IsTrue(content.PublishCulture(CultureType.Single(langFr, false)));
|
||||
|
||||
// now UK is available too
|
||||
content.SetCultureName("name-uk", langUk);
|
||||
|
||||
@@ -181,13 +181,13 @@ namespace Umbraco.Tests.Persistence.NPocoTests
|
||||
contentTypeService.Save(contentType);
|
||||
var content1 = MockedContent.CreateSimpleContent(contentType, "Tagged content 1", -1);
|
||||
content1.AssignTags("tags", new[] { "hello", "world", "some", "tags" });
|
||||
content1.PublishCulture();
|
||||
content1.PublishCulture(CultureType.Invariant);
|
||||
contentService.SaveAndPublish(content1);
|
||||
id2 = content1.Id;
|
||||
|
||||
var content2 = MockedContent.CreateSimpleContent(contentType, "Tagged content 2", -1);
|
||||
content2.AssignTags("tags", new[] { "hello", "world", "some", "tags" });
|
||||
content2.PublishCulture();
|
||||
content2.PublishCulture(CultureType.Invariant);
|
||||
contentService.SaveAndPublish(content2);
|
||||
id3 = content2.Id;
|
||||
|
||||
|
||||
@@ -141,8 +141,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
// publish = new edit version
|
||||
content1.SetValue("title", "title");
|
||||
((Content)content1).PublishCulture();
|
||||
((Content)content1).PublishedState = PublishedState.Publishing;
|
||||
content1.PublishCulture(CultureType.Invariant);
|
||||
content1.PublishedState = PublishedState.Publishing;
|
||||
repository.Save(content1);
|
||||
|
||||
versions.Add(content1.VersionId); // NEW VERSION
|
||||
@@ -203,8 +203,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
Assert.AreEqual(false, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
|
||||
|
||||
// publish = version
|
||||
((Content)content1).PublishCulture();
|
||||
((Content)content1).PublishedState = PublishedState.Publishing;
|
||||
content1.PublishCulture(CultureType.Invariant);
|
||||
content1.PublishedState = PublishedState.Publishing;
|
||||
repository.Save(content1);
|
||||
|
||||
versions.Add(content1.VersionId); // NEW VERSION
|
||||
@@ -239,8 +239,8 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// publish = new version
|
||||
content1.Name = "name-4";
|
||||
content1.SetValue("title", "title-4");
|
||||
((Content)content1).PublishCulture();
|
||||
((Content)content1).PublishedState = PublishedState.Publishing;
|
||||
content1.PublishCulture(CultureType.Invariant);
|
||||
content1.PublishedState = PublishedState.Publishing;
|
||||
repository.Save(content1);
|
||||
|
||||
versions.Add(content1.VersionId); // NEW VERSION
|
||||
@@ -654,7 +654,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
// publish them all
|
||||
foreach (var content in result)
|
||||
{
|
||||
content.PublishCulture();
|
||||
content.PublishCulture(CultureType.Invariant);
|
||||
repository.Save(content);
|
||||
}
|
||||
|
||||
|
||||
@@ -517,7 +517,7 @@ namespace Umbraco.Tests.Services
|
||||
allTags = tagService.GetAllContentTags();
|
||||
Assert.AreEqual(0, allTags.Count());
|
||||
|
||||
content1.PublishCulture();
|
||||
content1.PublishCulture(CultureType.Invariant);
|
||||
contentService.SaveAndPublish(content1);
|
||||
|
||||
Assert.IsTrue(content1.Published);
|
||||
@@ -601,7 +601,7 @@ namespace Umbraco.Tests.Services
|
||||
var allTags = tagService.GetAllContentTags();
|
||||
Assert.AreEqual(0, allTags.Count());
|
||||
|
||||
content1.PublishCulture();
|
||||
content1.PublishCulture(CultureType.Invariant);
|
||||
contentService.SaveAndPublish(content1);
|
||||
|
||||
tags = tagService.GetTagsForEntity(content2.Id);
|
||||
|
||||
@@ -732,8 +732,8 @@ namespace Umbraco.Tests.Services
|
||||
IContent content = new Content("content", Constants.System.Root, contentType);
|
||||
content.SetCultureName("content-fr", langFr.IsoCode);
|
||||
content.SetCultureName("content-en", langUk.IsoCode);
|
||||
content.PublishCulture(langFr.IsoCode);
|
||||
content.PublishCulture(langUk.IsoCode);
|
||||
content.PublishCulture(CultureType.Single(langFr.IsoCode, langFr.IsDefault));
|
||||
content.PublishCulture(CultureType.Single(langUk.IsoCode, langUk.IsDefault));
|
||||
Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode));
|
||||
Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode));
|
||||
|
||||
@@ -988,7 +988,7 @@ namespace Umbraco.Tests.Services
|
||||
|
||||
// content cannot publish values because they are invalid
|
||||
var propertyValidationService = new PropertyValidationService(Factory.GetInstance<PropertyEditorCollection>(), ServiceContext.DataTypeService);
|
||||
var isValid = propertyValidationService.IsPropertyDataValid(content, out var invalidProperties);
|
||||
var isValid = propertyValidationService.IsPropertyDataValid(content, out var invalidProperties, CultureType.Invariant);
|
||||
Assert.IsFalse(isValid);
|
||||
Assert.IsNotEmpty(invalidProperties);
|
||||
|
||||
@@ -1018,7 +1018,7 @@ namespace Umbraco.Tests.Services
|
||||
content.SetCultureName("name-fr", langFr.IsoCode);
|
||||
content.SetCultureName("name-da", langDa.IsoCode);
|
||||
|
||||
content.PublishCulture(langFr.IsoCode);
|
||||
content.PublishCulture(CultureType.Single(langFr.IsoCode, langFr.IsDefault));
|
||||
var result = ((ContentService)ServiceContext.ContentService).CommitDocumentChanges(content);
|
||||
Assert.IsTrue(result.Success);
|
||||
content = ServiceContext.ContentService.GetById(content.Id);
|
||||
@@ -1026,7 +1026,7 @@ namespace Umbraco.Tests.Services
|
||||
Assert.IsFalse(content.IsCulturePublished(langDa.IsoCode));
|
||||
|
||||
content.UnpublishCulture(langFr.IsoCode);
|
||||
content.PublishCulture(langDa.IsoCode);
|
||||
content.PublishCulture(CultureType.Single(langDa.IsoCode, langDa.IsDefault));
|
||||
|
||||
result = ((ContentService)ServiceContext.ContentService).CommitDocumentChanges(content);
|
||||
Assert.IsTrue(result.Success);
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace Umbraco.Tests.Services
|
||||
var result = new List<IContent>();
|
||||
ServiceContext.ContentTypeService.Save(contentType1);
|
||||
IContent lastParent = MockedContent.CreateSimpleContent(contentType1);
|
||||
lastParent.PublishCulture();
|
||||
lastParent.PublishCulture(CultureType.Invariant);
|
||||
ServiceContext.ContentService.SaveAndPublish(lastParent);
|
||||
result.Add(lastParent);
|
||||
//create 20 deep
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Tests.Services
|
||||
//only publish evens
|
||||
if (j % 2 == 0)
|
||||
{
|
||||
content.PublishCulture();
|
||||
content.PublishCulture(CultureType.Invariant);
|
||||
ServiceContext.ContentService.SaveAndPublish(content);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function umbNotificationList() {
|
||||
|
||||
var vm = this;
|
||||
|
||||
}
|
||||
|
||||
var umbNotificationListComponent = {
|
||||
templateUrl: 'views/components/content/umb-notification-list.html',
|
||||
bindings: {
|
||||
notifications: "<"
|
||||
},
|
||||
controllerAs: 'vm',
|
||||
controller: umbNotificationList
|
||||
};
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.component('umbNotificationList', umbNotificationListComponent);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,8 @@
|
||||
<span class="db" ng-repeat="notification in vm.notifications">
|
||||
<!-- These are server side notifications for messages, generally success/warning, validation messages handled separately -->
|
||||
<!-- Success = 3, Error = 2, Warning = 4 -->
|
||||
<span class="db umb-permission__description"
|
||||
ng-class="{'text-success': notification.type === 3, 'text-error': notification.type === 2 || notification.type === 4}">
|
||||
{{notification.message}}
|
||||
</span>
|
||||
</span>
|
||||
@@ -36,10 +36,8 @@
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<!-- These are server side notifications for successful messages, non successful messages are returned via validation errors -->
|
||||
<span class="db umb-permission__description text-success">{{notification.message}}</span>
|
||||
</span>
|
||||
<umb-notification-list notifications="variant.notifications" />
|
||||
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,10 +64,8 @@
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<!-- These are server side notifications for successful messages, non successful messages are returned via validation errors -->
|
||||
<span class="db umb-permission__description text-success">{{notification.message}}</span>
|
||||
</span>
|
||||
<umb-notification-list notifications="variant.notifications" />
|
||||
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -41,10 +41,8 @@
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<!-- These are server side notifications for successful messages, non successful messages are returned via validation errors -->
|
||||
<span class="db umb-permission__description text-success">{{notification.message}}</span>
|
||||
</span>
|
||||
<umb-notification-list notifications="variant.notifications" />
|
||||
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -170,10 +170,7 @@
|
||||
<div class="umb-permission__description text-error" ng-message="valServerField">{{scheduleSelectorForm.saveVariantReleaseDate.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<!-- These are server side notifications for successful messages, non successful messages are returned via validation errors -->
|
||||
<div class="umb-permission__description text-success">{{notification.message}}</div>
|
||||
</div>
|
||||
<umb-notification-list notifications="variant.notifications" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -34,9 +34,8 @@
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<span class="db umb-permission__description text-success">{{notification.message}}</span>
|
||||
</span>
|
||||
<umb-notification-list notifications="variant.notifications" />
|
||||
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -728,7 +728,7 @@ namespace Umbraco.Web.Editors
|
||||
break;
|
||||
}
|
||||
|
||||
var publishStatus = PublishBranchInternal(contentItem, false, out wasCancelled, out var successfulCultures);
|
||||
var publishStatus = PublishBranchInternal(contentItem, false, out wasCancelled, out var successfulCultures).ToList();
|
||||
|
||||
//global notifications
|
||||
AddMessageForPublishStatus(publishStatus, globalNotifications, successfulCultures);
|
||||
@@ -749,7 +749,7 @@ namespace Umbraco.Web.Editors
|
||||
break;
|
||||
}
|
||||
|
||||
var publishStatus = PublishBranchInternal(contentItem, true, out wasCancelled, out var successfulCultures);
|
||||
var publishStatus = PublishBranchInternal(contentItem, true, out wasCancelled, out var successfulCultures).ToList();
|
||||
|
||||
//global notifications
|
||||
AddMessageForPublishStatus(publishStatus, globalNotifications, successfulCultures);
|
||||
@@ -1341,7 +1341,7 @@ namespace Umbraco.Web.Editors
|
||||
foreach (var variant in cultureVariants.Where(x => x.Publish))
|
||||
{
|
||||
// publishing any culture, implies the invariant culture
|
||||
var valid = persistentContent.PublishCulture(variant.Culture);
|
||||
var valid = persistentContent.PublishCulture(CultureType.Single(variant.Culture, IsDefaultCulture(variant.Culture)));
|
||||
if (!valid)
|
||||
{
|
||||
AddCultureValidationError(variant.Culture, "speechBubbles/contentCultureValidationError");
|
||||
@@ -1942,12 +1942,12 @@ namespace Umbraco.Web.Editors
|
||||
/// <summary>
|
||||
/// Adds notification messages to the outbound display model for a given published status
|
||||
/// </summary>
|
||||
/// <param name="status"></param>
|
||||
/// <param name="statuses"></param>
|
||||
/// <param name="display"></param>
|
||||
/// <param name="successfulCultures">
|
||||
/// This is null when dealing with invariant content, else it's the cultures that were successfully published
|
||||
/// </param>
|
||||
private void AddMessageForPublishStatus(IEnumerable<PublishResult> statuses, INotificationModel display, string[] successfulCultures = null)
|
||||
private void AddMessageForPublishStatus(IReadOnlyCollection<PublishResult> statuses, INotificationModel display, string[] successfulCultures = null)
|
||||
{
|
||||
var totalStatusCount = statuses.Count();
|
||||
|
||||
@@ -2046,7 +2046,7 @@ namespace Umbraco.Web.Editors
|
||||
break;
|
||||
case PublishResultType.FailedPublishPathNotPublished:
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"{x.Content.Name} ({x.Content.Id})"));
|
||||
var names = string.Join(", ", status.Select(x => x.Content.Name));
|
||||
display.AddWarningNotification(
|
||||
Services.TextService.Localize("publish"),
|
||||
Services.TextService.Localize("publish/contentPublishedFailedByParent",
|
||||
@@ -2055,13 +2055,13 @@ namespace Umbraco.Web.Editors
|
||||
break;
|
||||
case PublishResultType.FailedPublishCancelledByEvent:
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"{x.Content.Name} ({x.Content.Id})"));
|
||||
var names = string.Join(", ", status.Select(x => x.Content.Name));
|
||||
AddCancelMessage(display, message: "publish/contentPublishedFailedByEvent", messageParams: new[] { names });
|
||||
}
|
||||
break;
|
||||
case PublishResultType.FailedPublishAwaitingRelease:
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"{x.Content.Name} ({x.Content.Id})"));
|
||||
var names = string.Join(", ", status.Select(x => x.Content.Name));
|
||||
display.AddWarningNotification(
|
||||
Services.TextService.Localize("publish"),
|
||||
Services.TextService.Localize("publish/contentPublishedFailedAwaitingRelease",
|
||||
@@ -2070,7 +2070,7 @@ namespace Umbraco.Web.Editors
|
||||
break;
|
||||
case PublishResultType.FailedPublishHasExpired:
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"{x.Content.Name} ({x.Content.Id})"));
|
||||
var names = string.Join(", ", status.Select(x => x.Content.Name));
|
||||
display.AddWarningNotification(
|
||||
Services.TextService.Localize("publish"),
|
||||
Services.TextService.Localize("publish/contentPublishedFailedExpired",
|
||||
@@ -2079,7 +2079,7 @@ namespace Umbraco.Web.Editors
|
||||
break;
|
||||
case PublishResultType.FailedPublishIsTrashed:
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"{x.Content.Name} ({x.Content.Id})"));
|
||||
var names = string.Join(", ", status.Select(x => x.Content.Name));
|
||||
display.AddWarningNotification(
|
||||
Services.TextService.Localize("publish"),
|
||||
Services.TextService.Localize("publish/contentPublishedFailedIsTrashed",
|
||||
@@ -2088,7 +2088,7 @@ namespace Umbraco.Web.Editors
|
||||
break;
|
||||
case PublishResultType.FailedPublishContentInvalid:
|
||||
{
|
||||
var names = string.Join(", ", status.Select(x => $"{x.Content.Name} ({x.Content.Id})"));
|
||||
var names = string.Join(", ", status.Select(x => x.Content.Name));
|
||||
display.AddWarningNotification(
|
||||
Services.TextService.Localize("publish"),
|
||||
Services.TextService.Localize("publish/contentPublishedFailedInvalid",
|
||||
@@ -2106,6 +2106,16 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the culture specified is the default culture
|
||||
/// </summary>
|
||||
/// <param name="culture"></param>
|
||||
/// <returns></returns>
|
||||
private bool IsDefaultCulture(string culture)
|
||||
{
|
||||
return _allLangs.Value.Any(x => x.Value.IsDefault && x.Key.InvariantEquals(culture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to map an <see cref="IContent"/> instance to a <see cref="ContentItemDisplay"/> and ensuring a language is present if required
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user