Hotfix: Move allow edit invariant from non default setting to content settings (#12960)
* Use ContentSettings instead of SecuritySettings for AllowEditInvariantFromNonDefault * Make it backwards compatible
This commit is contained in:
@@ -157,6 +157,7 @@ public class ContentSettings
|
||||
internal const bool StaticHideBackOfficeLogo = false;
|
||||
internal const bool StaticDisableDeleteWhenReferenced = false;
|
||||
internal const bool StaticDisableUnpublishWhenReferenced = false;
|
||||
internal const bool StaticAllowEditInvariantFromNonDefault = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value for the content notification settings.
|
||||
@@ -242,4 +243,10 @@ public class ContentSettings
|
||||
/// Get or sets the model representing the global content version cleanup policy
|
||||
/// </summary>
|
||||
public ContentVersionCleanupPolicySettings ContentVersionCleanupPolicy { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to allow editing invariant properties from a non-default language variation.
|
||||
/// </summary>
|
||||
[DefaultValue(StaticAllowEditInvariantFromNonDefault)]
|
||||
public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
|
||||
}
|
||||
|
||||
@@ -86,9 +86,10 @@ public class SecuritySettings
|
||||
[DefaultValue(StaticUserBypassTwoFactorForExternalLogins)]
|
||||
public bool UserBypassTwoFactorForExternalLogins { get; set; } = StaticUserBypassTwoFactorForExternalLogins;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to allow editing invariant properties from a non-default language variation.
|
||||
/// </summary>
|
||||
[DefaultValue(StaticAllowEditInvariantFromNonDefault)]
|
||||
public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to allow editing invariant properties from a non-default language variation.
|
||||
/// </summary>
|
||||
[Obsolete("Use ContentSettings.AllowEditFromInvariant instead")]
|
||||
[DefaultValue(StaticAllowEditInvariantFromNonDefault)]
|
||||
public bool AllowEditInvariantFromNonDefault { get; set; } = StaticAllowEditInvariantFromNonDefault;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
@@ -104,6 +105,20 @@ public static partial class UmbracoBuilderExtensions
|
||||
|
||||
builder.Services.Configure<RequestHandlerSettings>(options => options.MergeReplacements(builder.Config));
|
||||
|
||||
// TODO: Remove this in V12
|
||||
// This is to make the move of the AllowEditInvariantFromNonDefault setting from SecuritySettings to ContentSettings backwards compatible
|
||||
// If there is a value in security settings, but no value in content setting we'll use that value, otherwise content settings always wins.
|
||||
builder.Services.Configure<ContentSettings>(settings =>
|
||||
{
|
||||
var securitySettingsValue = builder.Config.GetSection($"{Constants.Configuration.ConfigSecurity}").GetValue<bool?>(nameof(SecuritySettings.AllowEditInvariantFromNonDefault));
|
||||
var contentSettingsValue = builder.Config.GetSection($"{Constants.Configuration.ConfigContent}").GetValue<bool?>(nameof(ContentSettings.AllowEditInvariantFromNonDefault));
|
||||
|
||||
if (securitySettingsValue is not null && contentSettingsValue is null)
|
||||
{
|
||||
settings.AllowEditInvariantFromNonDefault = securitySettingsValue.Value;
|
||||
}
|
||||
});
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
Services.AddUnique<IPropertyTypeUsageService, PropertyTypeUsageService>();
|
||||
Services.AddUnique<IDataTypeUsageService, DataTypeUsageService>();
|
||||
|
||||
Services.AddUnique<ICultureImpactFactory, CultureImpactFactory>();
|
||||
Services.AddUnique<ICultureImpactFactory>(provider => new CultureImpactFactory(provider.GetRequiredService<IOptionsMonitor<ContentSettings>>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class ContentVariantMapper
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IUserService _userService;
|
||||
private SecuritySettings _securitySettings;
|
||||
private ContentSettings _contentSettings;
|
||||
|
||||
public ContentVariantMapper(
|
||||
ILocalizationService localizationService,
|
||||
@@ -28,17 +28,36 @@ public class ContentVariantMapper
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
IContentService contentService,
|
||||
IUserService userService,
|
||||
IOptionsMonitor<SecuritySettings> securitySettings)
|
||||
IOptionsMonitor<ContentSettings> contentSettings)
|
||||
{
|
||||
_localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService));
|
||||
_localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService));
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
_contentService = contentService;
|
||||
_userService = userService;
|
||||
_securitySettings = securitySettings.CurrentValue;
|
||||
securitySettings.OnChange(settings => _securitySettings = settings);
|
||||
_contentSettings = contentSettings.CurrentValue;
|
||||
contentSettings.OnChange(settings => _contentSettings = settings);
|
||||
}
|
||||
|
||||
[Obsolete("Use constructor that takes all parameters instead")]
|
||||
public ContentVariantMapper(
|
||||
ILocalizationService localizationService,
|
||||
ILocalizedTextService localizedTextService,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
IContentService contentService,
|
||||
IUserService userService,
|
||||
IOptionsMonitor<SecuritySettings> securitySettings)
|
||||
: this(
|
||||
localizationService,
|
||||
localizedTextService,
|
||||
backOfficeSecurityAccessor,
|
||||
contentService,
|
||||
userService,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<ContentSettings>>())
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use constructor that takes all parameters instead")]
|
||||
public ContentVariantMapper(ILocalizationService localizationService, ILocalizedTextService localizedTextService)
|
||||
: this(
|
||||
localizationService,
|
||||
@@ -244,7 +263,7 @@ public class ContentVariantMapper
|
||||
if (variantDisplay.Language is null)
|
||||
{
|
||||
var defaultLanguageId = _localizationService.GetDefaultLanguageId();
|
||||
if (_securitySettings.AllowEditInvariantFromNonDefault || (defaultLanguageId.HasValue && group.HasAccessToLanguage(defaultLanguageId.Value)))
|
||||
if (_contentSettings.AllowEditInvariantFromNonDefault || (defaultLanguageId.HasValue && group.HasAccessToLanguage(defaultLanguageId.Value)))
|
||||
{
|
||||
hasAccess = true;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
public class CultureImpactFactory : ICultureImpactFactory
|
||||
{
|
||||
private SecuritySettings _securitySettings;
|
||||
private ContentSettings _contentSettings;
|
||||
|
||||
public CultureImpactFactory(IOptionsMonitor<SecuritySettings> securitySettings)
|
||||
public CultureImpactFactory(IOptionsMonitor<ContentSettings> contentSettings)
|
||||
{
|
||||
_securitySettings = securitySettings.CurrentValue;
|
||||
_contentSettings = contentSettings.CurrentValue;
|
||||
|
||||
securitySettings.OnChange(x => _securitySettings = x);
|
||||
contentSettings.OnChange(x => _contentSettings = x);
|
||||
}
|
||||
|
||||
[Obsolete("Use constructor that takes IOptionsMonitor<SecuritySettings> instead. Scheduled for removal in V12")]
|
||||
public CultureImpactFactory(IOptionsMonitor<SecuritySettings> securitySettings)
|
||||
: this(StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<ContentSettings>>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CultureImpact? Create(string? culture, bool isDefault, IContent content)
|
||||
{
|
||||
TryCreate(culture, isDefault, content.ContentType.Variations, true, _securitySettings.AllowEditInvariantFromNonDefault, out CultureImpact? impact);
|
||||
TryCreate(culture, isDefault, content.ContentType.Variations, true, _contentSettings.AllowEditInvariantFromNonDefault, out CultureImpact? impact);
|
||||
|
||||
return impact;
|
||||
}
|
||||
@@ -48,7 +56,7 @@ public class CultureImpactFactory : ICultureImpactFactory
|
||||
throw new ArgumentException("Culture \"*\" is not explicit.");
|
||||
}
|
||||
|
||||
return new CultureImpact(culture, isDefault, _securitySettings.AllowEditInvariantFromNonDefault);
|
||||
return new CultureImpact(culture, isDefault, _contentSettings.AllowEditInvariantFromNonDefault);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -569,7 +569,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{"minimumPasswordNonAlphaNum", _memberPasswordConfigurationSettings.GetMinNonAlphaNumericChars()},
|
||||
{"sanitizeTinyMce", _globalSettings.SanitizeTinyMce},
|
||||
{"dataTypesCanBeChanged", _dataTypesSettings.CanBeChanged.ToString()},
|
||||
{"allowEditInvariantFromNonDefault", _securitySettings.AllowEditInvariantFromNonDefault},
|
||||
{"allowEditInvariantFromNonDefault", _contentSettings.AllowEditInvariantFromNonDefault},
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,24 +13,25 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Models;
|
||||
[TestFixture]
|
||||
public class CultureImpactTests
|
||||
{
|
||||
private CultureImpactFactory BasicImpactFactory => createCultureImpactService();
|
||||
private CultureImpactFactory BasicImpactFactory => createCultureImpactService();
|
||||
|
||||
[Test]
|
||||
public void Get_Culture_For_Invariant_Errors()
|
||||
{
|
||||
var result = BasicImpactFactory.GetCultureForInvariantErrors(
|
||||
var result = BasicImpactFactory.GetCultureForInvariantErrors(
|
||||
Mock.Of<IContent>(x => x.Published == true),
|
||||
new[] { "en-US", "fr-FR" },
|
||||
"en-US");
|
||||
Assert.AreEqual("en-US", result); // default culture is being saved so use it
|
||||
|
||||
result = BasicImpactFactory.GetCultureForInvariantErrors(
|
||||
result = BasicImpactFactory.GetCultureForInvariantErrors(
|
||||
Mock.Of<IContent>(x => x.Published == false),
|
||||
new[] { "fr-FR" },
|
||||
"en-US");
|
||||
Assert.AreEqual("fr-FR", result); // default culture not being saved with not published version, use the first culture being saved
|
||||
Assert.AreEqual("fr-FR",
|
||||
result); // default culture not being saved with not published version, use the first culture being saved
|
||||
|
||||
result = BasicImpactFactory.GetCultureForInvariantErrors(
|
||||
result = BasicImpactFactory.GetCultureForInvariantErrors(
|
||||
Mock.Of<IContent>(x => x.Published == true),
|
||||
new[] { "fr-FR" },
|
||||
"en-US");
|
||||
@@ -70,7 +71,7 @@ public class CultureImpactTests
|
||||
[Test]
|
||||
public void Explicit_Default_Culture()
|
||||
{
|
||||
var impact = BasicImpactFactory.ImpactExplicit("en-US", true);
|
||||
var impact = BasicImpactFactory.ImpactExplicit("en-US", true);
|
||||
|
||||
Assert.AreEqual(impact.Culture, "en-US");
|
||||
|
||||
@@ -85,7 +86,7 @@ public class CultureImpactTests
|
||||
[Test]
|
||||
public void Explicit_NonDefault_Culture()
|
||||
{
|
||||
var impact = BasicImpactFactory.ImpactExplicit("en-US", false);
|
||||
var impact = BasicImpactFactory.ImpactExplicit("en-US", false);
|
||||
|
||||
Assert.AreEqual(impact.Culture, "en-US");
|
||||
|
||||
@@ -100,10 +101,11 @@ public class CultureImpactTests
|
||||
[Test]
|
||||
public void TryCreate_Explicit_Default_Culture()
|
||||
{
|
||||
var success = BasicImpactFactory.TryCreate("en-US", true, ContentVariation.Culture, false, false, out var impact);
|
||||
var success =
|
||||
BasicImpactFactory.TryCreate("en-US", true, ContentVariation.Culture, false, false, out var impact);
|
||||
Assert.IsTrue(success);
|
||||
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.AreEqual(impact.Culture, "en-US");
|
||||
|
||||
Assert.IsTrue(impact.ImpactsInvariantProperties);
|
||||
@@ -117,10 +119,11 @@ public class CultureImpactTests
|
||||
[Test]
|
||||
public void TryCreate_Explicit_NonDefault_Culture()
|
||||
{
|
||||
var success = BasicImpactFactory.TryCreate("en-US", false, ContentVariation.Culture, false, false, out var impact);
|
||||
var success =
|
||||
BasicImpactFactory.TryCreate("en-US", false, ContentVariation.Culture, false, false, out var impact);
|
||||
Assert.IsTrue(success);
|
||||
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.AreEqual(impact.Culture, "en-US");
|
||||
|
||||
Assert.IsFalse(impact.ImpactsInvariantProperties);
|
||||
@@ -137,10 +140,10 @@ public class CultureImpactTests
|
||||
var success = BasicImpactFactory.TryCreate("*", false, ContentVariation.Nothing, false, false, out var impact);
|
||||
Assert.IsTrue(success);
|
||||
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.AreEqual(impact.Culture, null);
|
||||
|
||||
Assert.AreSame(BasicImpactFactory.ImpactInvariant(), impact);
|
||||
Assert.AreSame(BasicImpactFactory.ImpactInvariant(), impact);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -149,10 +152,10 @@ public class CultureImpactTests
|
||||
var success = BasicImpactFactory.TryCreate("*", false, ContentVariation.Culture, false, false, out var impact);
|
||||
Assert.IsTrue(success);
|
||||
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.IsNotNull(impact);
|
||||
Assert.AreEqual(impact.Culture, "*");
|
||||
|
||||
Assert.AreSame(BasicImpactFactory.ImpactAll(), impact);
|
||||
Assert.AreSame(BasicImpactFactory.ImpactAll(), impact);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -168,28 +171,27 @@ public class CultureImpactTests
|
||||
var success = BasicImpactFactory.TryCreate(null, false, ContentVariation.Nothing, false, false, out var impact);
|
||||
Assert.IsTrue(success);
|
||||
|
||||
Assert.AreSame(BasicImpactFactory.ImpactInvariant(), impact);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void Edit_Invariant_From_Non_Default_Impacts_Invariant_Properties(bool allowEditInvariantFromNonDefault)
|
||||
{
|
||||
var sut = createCultureImpactService(new SecuritySettings { AllowEditInvariantFromNonDefault = allowEditInvariantFromNonDefault });
|
||||
var impact = sut.ImpactExplicit("da", false);
|
||||
|
||||
Assert.AreEqual(allowEditInvariantFromNonDefault, impact.ImpactsAlsoInvariantProperties);
|
||||
Assert.AreSame(BasicImpactFactory.ImpactInvariant(), impact);
|
||||
}
|
||||
|
||||
private CultureImpactFactory createCultureImpactService(SecuritySettings securitySettings = null)
|
||||
[Test]
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void Edit_Invariant_From_Non_Default_Impacts_Invariant_Properties(bool allowEditInvariantFromNonDefault)
|
||||
{
|
||||
var sut = createCultureImpactService(new ContentSettings
|
||||
{
|
||||
securitySettings ??= new SecuritySettings
|
||||
{
|
||||
AllowEditInvariantFromNonDefault = false,
|
||||
};
|
||||
AllowEditInvariantFromNonDefault = allowEditInvariantFromNonDefault
|
||||
});
|
||||
var impact = sut.ImpactExplicit("da", false);
|
||||
|
||||
return new CultureImpactFactory(new TestOptionsMonitor<SecuritySettings>(securitySettings));
|
||||
}
|
||||
Assert.AreEqual(allowEditInvariantFromNonDefault, impact.ImpactsAlsoInvariantProperties);
|
||||
}
|
||||
|
||||
private CultureImpactFactory createCultureImpactService(ContentSettings contentSettings = null)
|
||||
{
|
||||
contentSettings ??= new ContentSettings { AllowEditInvariantFromNonDefault = false, };
|
||||
|
||||
return new CultureImpactFactory(new TestOptionsMonitor<ContentSettings>(contentSettings));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user