Migrations: Handles rich text blocks created with TinyMCE in convert local links migration and refreshes internal datatype cache following migration requiring cache rebuild (closes #20885) (#20887)
Handles rich text blocks created with TinyMCE in convert local links migration. Refreshes internal datatype cache following migration requiring cache rebuild.
This commit is contained in:
@@ -23,4 +23,11 @@ public class RichTextBlockValue : BlockValue<RichTextBlockLayoutItem>
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public override string PropertyEditorAlias => Constants.PropertyEditors.Aliases.RichText;
|
public override string PropertyEditorAlias => Constants.PropertyEditors.Aliases.RichText;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
#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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ public interface IPublishedContentTypeFactory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
PublishedDataType GetDataType(int id);
|
PublishedDataType GetDataType(int id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the internal data type cache.
|
||||||
|
/// </summary>
|
||||||
|
void ClearDataTypeCache()
|
||||||
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies the factory of datatype changes.
|
/// Notifies the factory of datatype changes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -65,6 +65,22 @@ public class PublishedContentTypeFactory : IPublishedContentTypeFactory
|
|||||||
return dataType;
|
return dataType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void NotifyDataTypeChanges(params int[] ids)
|
public void NotifyDataTypeChanges(params int[] ids)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ using Microsoft.Extensions.Logging;
|
|||||||
using OpenIddict.Abstractions;
|
using OpenIddict.Abstractions;
|
||||||
using Umbraco.Cms.Core;
|
using Umbraco.Cms.Core;
|
||||||
using Umbraco.Cms.Core.Cache;
|
using Umbraco.Cms.Core.Cache;
|
||||||
|
using Umbraco.Cms.Core.DependencyInjection;
|
||||||
using Umbraco.Cms.Core.Migrations;
|
using Umbraco.Cms.Core.Migrations;
|
||||||
|
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||||
using Umbraco.Cms.Core.PublishedCache;
|
using Umbraco.Cms.Core.PublishedCache;
|
||||||
using Umbraco.Cms.Core.Scoping;
|
using Umbraco.Cms.Core.Scoping;
|
||||||
using Umbraco.Cms.Core.Services;
|
using Umbraco.Cms.Core.Services;
|
||||||
@@ -47,9 +49,12 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
|
|||||||
private readonly DistributedCache _distributedCache;
|
private readonly DistributedCache _distributedCache;
|
||||||
private readonly IScopeAccessor _scopeAccessor;
|
private readonly IScopeAccessor _scopeAccessor;
|
||||||
private readonly ICoreScopeProvider _scopeProvider;
|
private readonly ICoreScopeProvider _scopeProvider;
|
||||||
|
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
|
||||||
|
|
||||||
private bool _rebuildCache;
|
private bool _rebuildCache;
|
||||||
private bool _invalidateBackofficeUserAccess;
|
private bool _invalidateBackofficeUserAccess;
|
||||||
|
|
||||||
|
[Obsolete("Please use the constructor taking all parameters. Scheduled for removal in Umbraco 19.")]
|
||||||
public MigrationPlanExecutor(
|
public MigrationPlanExecutor(
|
||||||
ICoreScopeProvider scopeProvider,
|
ICoreScopeProvider scopeProvider,
|
||||||
IScopeAccessor scopeAccessor,
|
IScopeAccessor scopeAccessor,
|
||||||
@@ -61,6 +66,33 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
|
|||||||
IKeyValueService keyValueService,
|
IKeyValueService keyValueService,
|
||||||
IServiceScopeFactory serviceScopeFactory,
|
IServiceScopeFactory serviceScopeFactory,
|
||||||
AppCaches appCaches)
|
AppCaches appCaches)
|
||||||
|
: this(
|
||||||
|
scopeProvider,
|
||||||
|
scopeAccessor,
|
||||||
|
loggerFactory,
|
||||||
|
migrationBuilder,
|
||||||
|
databaseFactory,
|
||||||
|
databaseCacheRebuilder,
|
||||||
|
distributedCache,
|
||||||
|
keyValueService,
|
||||||
|
serviceScopeFactory,
|
||||||
|
appCaches,
|
||||||
|
StaticServiceProvider.Instance.GetRequiredService<IPublishedContentTypeFactory>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
_scopeProvider = scopeProvider;
|
||||||
_scopeAccessor = scopeAccessor;
|
_scopeAccessor = scopeAccessor;
|
||||||
@@ -72,6 +104,7 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
|
|||||||
_serviceScopeFactory = serviceScopeFactory;
|
_serviceScopeFactory = serviceScopeFactory;
|
||||||
_appCaches = appCaches;
|
_appCaches = appCaches;
|
||||||
_distributedCache = distributedCache;
|
_distributedCache = distributedCache;
|
||||||
|
_publishedContentTypeFactory = publishedContentTypeFactory;
|
||||||
_logger = _loggerFactory.CreateLogger<MigrationPlanExecutor>();
|
_logger = _loggerFactory.CreateLogger<MigrationPlanExecutor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +302,7 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
|
|||||||
_appCaches.IsolatedCaches.ClearAllCaches();
|
_appCaches.IsolatedCaches.ClearAllCaches();
|
||||||
await _databaseCacheRebuilder.RebuildAsync(false);
|
await _databaseCacheRebuilder.RebuildAsync(false);
|
||||||
_distributedCache.RefreshAllPublishedSnapshot();
|
_distributedCache.RefreshAllPublishedSnapshot();
|
||||||
|
_publishedContentTypeFactory.ClearDataTypeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RevokeBackofficeTokens()
|
private async Task RevokeBackofficeTokens()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Umbraco.Cms.Core.Cache;
|
|||||||
using Umbraco.Cms.Core.Configuration;
|
using Umbraco.Cms.Core.Configuration;
|
||||||
using Umbraco.Cms.Core.Events;
|
using Umbraco.Cms.Core.Events;
|
||||||
using Umbraco.Cms.Core.Migrations;
|
using Umbraco.Cms.Core.Migrations;
|
||||||
|
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||||
using Umbraco.Cms.Core.PublishedCache;
|
using Umbraco.Cms.Core.PublishedCache;
|
||||||
using Umbraco.Cms.Core.Scoping;
|
using Umbraco.Cms.Core.Scoping;
|
||||||
using Umbraco.Cms.Core.Services;
|
using Umbraco.Cms.Core.Services;
|
||||||
@@ -38,6 +39,7 @@ internal sealed class AdvancedMigrationTests : UmbracoIntegrationTest
|
|||||||
private IServiceScopeFactory ServiceScopeFactory => GetRequiredService<IServiceScopeFactory>();
|
private IServiceScopeFactory ServiceScopeFactory => GetRequiredService<IServiceScopeFactory>();
|
||||||
private DistributedCache DistributedCache => GetRequiredService<DistributedCache>();
|
private DistributedCache DistributedCache => GetRequiredService<DistributedCache>();
|
||||||
private IDatabaseCacheRebuilder DatabaseCacheRebuilder => GetRequiredService<IDatabaseCacheRebuilder>();
|
private IDatabaseCacheRebuilder DatabaseCacheRebuilder => GetRequiredService<IDatabaseCacheRebuilder>();
|
||||||
|
private IPublishedContentTypeFactory PublishedContentTypeFactory => GetRequiredService<IPublishedContentTypeFactory>();
|
||||||
private IMigrationPlanExecutor MigrationPlanExecutor => new MigrationPlanExecutor(
|
private IMigrationPlanExecutor MigrationPlanExecutor => new MigrationPlanExecutor(
|
||||||
CoreScopeProvider,
|
CoreScopeProvider,
|
||||||
ScopeAccessor,
|
ScopeAccessor,
|
||||||
@@ -48,7 +50,8 @@ internal sealed class AdvancedMigrationTests : UmbracoIntegrationTest
|
|||||||
DistributedCache,
|
DistributedCache,
|
||||||
Mock.Of<IKeyValueService>(),
|
Mock.Of<IKeyValueService>(),
|
||||||
ServiceScopeFactory,
|
ServiceScopeFactory,
|
||||||
AppCaches.NoCache);
|
AppCaches.NoCache,
|
||||||
|
PublishedContentTypeFactory);
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task CreateTableOfTDtoAsync()
|
public async Task CreateTableOfTDtoAsync()
|
||||||
|
|||||||
@@ -110,15 +110,16 @@ public class RichTextPropertyEditorHelperTests
|
|||||||
Assert.IsNull(value.Blocks);
|
Assert.IsNull(value.Blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[TestCase(Constants.PropertyEditors.Aliases.RichText)]
|
||||||
public void Can_Parse_Blocks_With_Both_Content_And_Settings()
|
[TestCase("Umbraco.TinyMCE")]
|
||||||
|
public void Can_Parse_Blocks_With_Both_Content_And_Settings(string propertyEditorAlias)
|
||||||
{
|
{
|
||||||
const string input = """
|
string input = """
|
||||||
{
|
{
|
||||||
"markup": "<p>this is some markup</p><umb-rte-block data-content-key=\"36cc710a-d8a6-45d0-a07f-7bbd8742cf02\"><!--Umbraco-Block--></umb-rte-block>",
|
"markup": "<p>this is some markup</p><umb-rte-block data-content-key=\"36cc710a-d8a6-45d0-a07f-7bbd8742cf02\"><!--Umbraco-Block--></umb-rte-block>",
|
||||||
"blocks": {
|
"blocks": {
|
||||||
"layout": {
|
"layout": {
|
||||||
"Umbraco.RichText": [{
|
"[PropertyEditorAlias]": [{
|
||||||
"contentKey": "36cc710a-d8a6-45d0-a07f-7bbd8742cf02",
|
"contentKey": "36cc710a-d8a6-45d0-a07f-7bbd8742cf02",
|
||||||
"settingsKey": "d2eeef66-4111-42f4-a164-7a523eaffbc2"
|
"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);
|
var result = RichTextPropertyEditorHelper.TryParseRichTextEditorValue(input, JsonSerializer(), Logger(), out RichTextEditorValue? value);
|
||||||
Assert.IsTrue(result);
|
Assert.IsTrue(result);
|
||||||
@@ -180,6 +182,12 @@ public class RichTextPropertyEditorHelperTests
|
|||||||
Assert.AreEqual("settingsPropertyAlias", settingsProperties.First().Alias);
|
Assert.AreEqual("settingsPropertyAlias", settingsProperties.First().Alias);
|
||||||
Assert.AreEqual("A settings property value", settingsProperties.First().Value);
|
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]
|
[Test]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using NUnit.Framework;
|
|||||||
using Umbraco.Cms.Core.Cache;
|
using Umbraco.Cms.Core.Cache;
|
||||||
using Umbraco.Cms.Core.Configuration.Models;
|
using Umbraco.Cms.Core.Configuration.Models;
|
||||||
using Umbraco.Cms.Core.Events;
|
using Umbraco.Cms.Core.Events;
|
||||||
|
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||||
using Umbraco.Cms.Core.PublishedCache;
|
using Umbraco.Cms.Core.PublishedCache;
|
||||||
using Umbraco.Cms.Core.Services;
|
using Umbraco.Cms.Core.Services;
|
||||||
using Umbraco.Cms.Core.Sync;
|
using Umbraco.Cms.Core.Sync;
|
||||||
@@ -85,7 +86,8 @@ public class MigrationPlanTests
|
|||||||
distributedCache,
|
distributedCache,
|
||||||
Mock.Of<IKeyValueService>(),
|
Mock.Of<IKeyValueService>(),
|
||||||
Mock.Of<IServiceScopeFactory>(),
|
Mock.Of<IServiceScopeFactory>(),
|
||||||
appCaches);
|
appCaches,
|
||||||
|
Mock.Of<IPublishedContentTypeFactory>());
|
||||||
|
|
||||||
var plan = new MigrationPlan("default")
|
var plan = new MigrationPlan("default")
|
||||||
.From(string.Empty)
|
.From(string.Empty)
|
||||||
|
|||||||
Reference in New Issue
Block a user