diff --git a/src/Umbraco.Core/Models/Blocks/RichTextBlockValue.cs b/src/Umbraco.Core/Models/Blocks/RichTextBlockValue.cs index 6cbab55693..3053e02d8b 100644 --- a/src/Umbraco.Core/Models/Blocks/RichTextBlockValue.cs +++ b/src/Umbraco.Core/Models/Blocks/RichTextBlockValue.cs @@ -23,4 +23,11 @@ public class RichTextBlockValue : BlockValue /// [JsonIgnore] public override string PropertyEditorAlias => Constants.PropertyEditors.Aliases.RichText; + + /// +#pragma warning disable CS0672 // Member overrides obsolete member +#pragma warning disable CS0618 // Type or member is obsolete + public override bool SupportsBlockLayoutAlias(string alias) => base.SupportsBlockLayoutAlias(alias) || alias.Equals("Umbraco.TinyMCE"); +#pragma warning restore CS0618 // Type or member is obsolete +#pragma warning restore CS0672 // Member overrides obsolete member } diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContentTypeFactory.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContentTypeFactory.cs index 009666aab5..9a5a14d7d4 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContentTypeFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContentTypeFactory.cs @@ -53,6 +53,12 @@ public interface IPublishedContentTypeFactory /// PublishedDataType GetDataType(int id); + /// + /// Clears the internal data type cache. + /// + void ClearDataTypeCache() + { } + /// /// Notifies the factory of datatype changes. /// diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs index 32fab1b539..7ea8779718 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeFactory.cs @@ -65,6 +65,22 @@ public class PublishedContentTypeFactory : IPublishedContentTypeFactory return dataType; } + /// + public void ClearDataTypeCache() + { + if (_publishedDataTypes is null) + { + // Not initialized yet, so skip and avoid lock + return; + } + + lock (_publishedDataTypesLocker) + { + // Clear cache (and let it lazy initialize again later) + _publishedDataTypes = null; + } + } + /// public void NotifyDataTypeChanges(params int[] ids) { diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs b/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs index 878d0e4d3b..45b1ebfbd4 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs @@ -7,6 +7,7 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Migrations; using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Security; @@ -51,9 +52,12 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor private readonly DistributedCache _distributedCache; private readonly IScopeAccessor _scopeAccessor; private readonly ICoreScopeProvider _scopeProvider; + private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; + private bool _rebuildCache; private bool _invalidateBackofficeUserAccess; + [Obsolete("Please use the constructor taking all parameters. Scheduled for removal in Umbraco 19.")] public MigrationPlanExecutor( ICoreScopeProvider scopeProvider, IScopeAccessor scopeAccessor, @@ -65,6 +69,33 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor IKeyValueService keyValueService, IServiceScopeFactory serviceScopeFactory, AppCaches appCaches) + : this( + scopeProvider, + scopeAccessor, + loggerFactory, + migrationBuilder, + databaseFactory, + databaseCacheRebuilder, + distributedCache, + keyValueService, + serviceScopeFactory, + appCaches, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + + public MigrationPlanExecutor( + ICoreScopeProvider scopeProvider, + IScopeAccessor scopeAccessor, + ILoggerFactory loggerFactory, + IMigrationBuilder migrationBuilder, + IUmbracoDatabaseFactory databaseFactory, + IDatabaseCacheRebuilder databaseCacheRebuilder, + DistributedCache distributedCache, + IKeyValueService keyValueService, + IServiceScopeFactory serviceScopeFactory, + AppCaches appCaches, + IPublishedContentTypeFactory publishedContentTypeFactory) { _scopeProvider = scopeProvider; _scopeAccessor = scopeAccessor; @@ -76,6 +107,7 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor _serviceScopeFactory = serviceScopeFactory; _appCaches = appCaches; _distributedCache = distributedCache; + _publishedContentTypeFactory = publishedContentTypeFactory; _logger = _loggerFactory.CreateLogger(); } @@ -301,6 +333,7 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor _appCaches.IsolatedCaches.ClearAllCaches(); await _databaseCacheRebuilder.RebuildAsync(false); _distributedCache.RefreshAllPublishedSnapshot(); + _publishedContentTypeFactory.ClearDataTypeCache(); } private async Task RevokeBackofficeTokens() diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Migrations/AdvancedMigrationTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Migrations/AdvancedMigrationTests.cs index b6fe2f48ed..444f94c218 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Migrations/AdvancedMigrationTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Migrations/AdvancedMigrationTests.cs @@ -10,6 +10,7 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Migrations; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; @@ -38,6 +39,7 @@ internal sealed class AdvancedMigrationTests : UmbracoIntegrationTest private IServiceScopeFactory ServiceScopeFactory => GetRequiredService(); private DistributedCache DistributedCache => GetRequiredService(); private IDatabaseCacheRebuilder DatabaseCacheRebuilder => GetRequiredService(); + private IPublishedContentTypeFactory PublishedContentTypeFactory => GetRequiredService(); private IMigrationPlanExecutor MigrationPlanExecutor => new MigrationPlanExecutor( CoreScopeProvider, ScopeAccessor, @@ -48,7 +50,8 @@ internal sealed class AdvancedMigrationTests : UmbracoIntegrationTest DistributedCache, Mock.Of(), ServiceScopeFactory, - AppCaches.NoCache); + AppCaches.NoCache, + PublishedContentTypeFactory); [Test] public async Task CreateTableOfTDtoAsync() diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/RichTextPropertyEditorHelperTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/RichTextPropertyEditorHelperTests.cs index 892e08cdd2..212d13687f 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/RichTextPropertyEditorHelperTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/PropertyEditors/RichTextPropertyEditorHelperTests.cs @@ -110,15 +110,16 @@ public class RichTextPropertyEditorHelperTests Assert.IsNull(value.Blocks); } - [Test] - public void Can_Parse_Blocks_With_Both_Content_And_Settings() + [TestCase(Constants.PropertyEditors.Aliases.RichText)] + [TestCase("Umbraco.TinyMCE")] + public void Can_Parse_Blocks_With_Both_Content_And_Settings(string propertyEditorAlias) { - const string input = """ + string input = """ { "markup": "

this is some markup

", "blocks": { "layout": { - "Umbraco.RichText": [{ + "[PropertyEditorAlias]": [{ "contentKey": "36cc710a-d8a6-45d0-a07f-7bbd8742cf02", "settingsKey": "d2eeef66-4111-42f4-a164-7a523eaffbc2" } @@ -143,6 +144,7 @@ public class RichTextPropertyEditorHelperTests } } """; + input = input.Replace("[PropertyEditorAlias]", propertyEditorAlias); var result = RichTextPropertyEditorHelper.TryParseRichTextEditorValue(input, JsonSerializer(), Logger(), out RichTextEditorValue? value); Assert.IsTrue(result); @@ -180,6 +182,12 @@ public class RichTextPropertyEditorHelperTests Assert.AreEqual("settingsPropertyAlias", settingsProperties.First().Alias); Assert.AreEqual("A settings property value", settingsProperties.First().Value); }); + + Assert.IsTrue(value.Blocks.Layout.ContainsKey(Constants.PropertyEditors.Aliases.RichText)); + var layout = value.Blocks.Layout[Constants.PropertyEditors.Aliases.RichText]; + Assert.AreEqual(1, layout.Count()); + Assert.AreEqual(Guid.Parse("36cc710a-d8a6-45d0-a07f-7bbd8742cf02"), layout.First().ContentKey); + Assert.AreEqual(Guid.Parse("d2eeef66-4111-42f4-a164-7a523eaffbc2"), layout.First().SettingsKey); } [Test] diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs index 261d41128d..a38c342945 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Migrations/MigrationPlanTests.cs @@ -12,6 +12,7 @@ using NUnit.Framework; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Sync; @@ -85,7 +86,8 @@ public class MigrationPlanTests distributedCache, Mock.Of(), Mock.Of(), - appCaches); + appCaches, + Mock.Of()); var plan = new MigrationPlan("default") .From(string.Empty)