Skip to content

Commit 0a56aaa

Browse files
authored
Fix mistakes in 15.0.0 migrations (#17814)
* Fix ConvertLocalLinks migration and add a new migration in case the old one has already run * RebuildCache * Clear cache means clear ALL caches * Fix Block Markup recursion * Fix Unittest mock constructor
1 parent e8c4fb9 commit 0a56aaa

File tree

10 files changed

+465
-7
lines changed

10 files changed

+465
-7
lines changed

src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor
4747
private readonly IDatabaseCacheRebuilder _databaseCacheRebuilder;
4848
private readonly IKeyValueService _keyValueService;
4949
private readonly IServiceScopeFactory _serviceScopeFactory;
50+
private readonly AppCaches _appCaches;
5051
private readonly DistributedCache _distributedCache;
5152
private readonly IScopeAccessor _scopeAccessor;
5253
private readonly ICoreScopeProvider _scopeProvider;
@@ -62,7 +63,8 @@ public MigrationPlanExecutor(
6263
IDatabaseCacheRebuilder databaseCacheRebuilder,
6364
DistributedCache distributedCache,
6465
IKeyValueService keyValueService,
65-
IServiceScopeFactory serviceScopeFactory)
66+
IServiceScopeFactory serviceScopeFactory,
67+
AppCaches appCaches)
6668
{
6769
_scopeProvider = scopeProvider;
6870
_scopeAccessor = scopeAccessor;
@@ -72,10 +74,36 @@ public MigrationPlanExecutor(
7274
_databaseCacheRebuilder = databaseCacheRebuilder;
7375
_keyValueService = keyValueService;
7476
_serviceScopeFactory = serviceScopeFactory;
77+
_appCaches = appCaches;
7578
_distributedCache = distributedCache;
7679
_logger = _loggerFactory.CreateLogger<MigrationPlanExecutor>();
7780
}
7881

82+
[Obsolete("Use the non obsoleted constructor instead. Scheduled for removal in v17")]
83+
public MigrationPlanExecutor(
84+
ICoreScopeProvider scopeProvider,
85+
IScopeAccessor scopeAccessor,
86+
ILoggerFactory loggerFactory,
87+
IMigrationBuilder migrationBuilder,
88+
IUmbracoDatabaseFactory databaseFactory,
89+
IDatabaseCacheRebuilder databaseCacheRebuilder,
90+
DistributedCache distributedCache,
91+
IKeyValueService keyValueService,
92+
IServiceScopeFactory serviceScopeFactory)
93+
: this(
94+
scopeProvider,
95+
scopeAccessor,
96+
loggerFactory,
97+
migrationBuilder,
98+
databaseFactory,
99+
databaseCacheRebuilder,
100+
distributedCache,
101+
keyValueService,
102+
serviceScopeFactory,
103+
StaticServiceProvider.Instance.GetRequiredService<AppCaches>())
104+
{
105+
}
106+
79107
public string Execute(MigrationPlan plan, string fromState) => ExecutePlan(plan, fromState).FinalState;
80108

81109
/// <summary>
@@ -303,6 +331,8 @@ private void RunMigration(Type migrationType, MigrationContext context)
303331

304332
private void RebuildCache()
305333
{
334+
_appCaches.RuntimeCache.Clear();
335+
_appCaches.IsolatedCaches.ClearAllCaches();
306336
_databaseCacheRebuilder.Rebuild();
307337
_distributedCache.RefreshAllPublishedSnapshot();
308338
}

src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,6 @@ protected virtual void DefinePlan()
105105
To<V_15_0_0.ConvertRichTextEditorProperties>("{37875E80-5CDD-42FF-A21A-7D4E3E23E0ED}");
106106
To<V_15_0_0.ConvertLocalLinks>("{42E44F9E-7262-4269-922D-7310CB48E724}");
107107
To<V_15_1_0.RebuildCacheMigration>("{7B51B4DE-5574-4484-993E-05D12D9ED703}");
108+
To<V_15_1_0.FixConvertLocalLinks>("{F3D3EF46-1B1F-47DB-B437-7D573EEDEB98}");
108109
}
109110
}

src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/ConvertLocalLinks.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System.Collections.Concurrent;
2+
using Microsoft.Extensions.DependencyInjection;
23
using Microsoft.Extensions.Logging;
34
using NPoco;
45
using Umbraco.Cms.Core;
6+
using Umbraco.Cms.Core.DependencyInjection;
57
using Umbraco.Cms.Core.Models;
68
using Umbraco.Cms.Core.Models.Editors;
79
using Umbraco.Cms.Core.Scoping;
@@ -26,7 +28,9 @@ public class ConvertLocalLinks : MigrationBase
2628
private readonly LocalLinkProcessor _localLinkProcessor;
2729
private readonly IMediaTypeService _mediaTypeService;
2830
private readonly ICoreScopeProvider _coreScopeProvider;
31+
private readonly LocalLinkMigrationTracker _linkMigrationTracker;
2932

33+
[Obsolete("Use non obsoleted contructor instead")]
3034
public ConvertLocalLinks(
3135
IMigrationContext context,
3236
IUmbracoContextFactory umbracoContextFactory,
@@ -37,7 +41,8 @@ public ConvertLocalLinks(
3741
IJsonSerializer jsonSerializer,
3842
LocalLinkProcessor localLinkProcessor,
3943
IMediaTypeService mediaTypeService,
40-
ICoreScopeProvider coreScopeProvider)
44+
ICoreScopeProvider coreScopeProvider,
45+
LocalLinkMigrationTracker linkMigrationTracker)
4146
: base(context)
4247
{
4348
_umbracoContextFactory = umbracoContextFactory;
@@ -49,6 +54,33 @@ public ConvertLocalLinks(
4954
_localLinkProcessor = localLinkProcessor;
5055
_mediaTypeService = mediaTypeService;
5156
_coreScopeProvider = coreScopeProvider;
57+
_linkMigrationTracker = linkMigrationTracker;
58+
}
59+
60+
public ConvertLocalLinks(
61+
IMigrationContext context,
62+
IUmbracoContextFactory umbracoContextFactory,
63+
IContentTypeService contentTypeService,
64+
ILogger<ConvertLocalLinks> logger,
65+
IDataTypeService dataTypeService,
66+
ILanguageService languageService,
67+
IJsonSerializer jsonSerializer,
68+
LocalLinkProcessor localLinkProcessor,
69+
IMediaTypeService mediaTypeService,
70+
ICoreScopeProvider coreScopeProvider)
71+
: this(
72+
context,
73+
umbracoContextFactory,
74+
contentTypeService,
75+
logger,
76+
dataTypeService,
77+
languageService,
78+
jsonSerializer,
79+
localLinkProcessor,
80+
mediaTypeService,
81+
coreScopeProvider,
82+
StaticServiceProvider.Instance.GetRequiredService<LocalLinkMigrationTracker>())
83+
{
5284
}
5385

5486
protected override void Migrate()
@@ -97,6 +129,9 @@ protected override void Migrate()
97129
propertyEditorAlias);
98130
}
99131
}
132+
133+
_linkMigrationTracker.MarkFixedMigrationRan();
134+
RebuildCache = true;
100135
}
101136

102137
private bool ProcessPropertyTypes(IPropertyType[] propertyTypes, IDictionary<int, ILanguage> languagesById)

src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/LocalLinks/ConvertLocalLinkComposer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@ public void Compose(IUmbracoBuilder builder)
1313
builder.Services.AddSingleton<ITypedLocalLinkProcessor, LocalLinkBlockGridProcessor>();
1414
builder.Services.AddSingleton<ITypedLocalLinkProcessor, LocalLinkRteProcessor>();
1515
builder.Services.AddSingleton<LocalLinkProcessor>();
16+
builder.Services.AddSingleton<LocalLinkProcessorForFaultyLinks>();
17+
builder.Services.AddSingleton<LocalLinkMigrationTracker>();
1618
}
1719
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0.LocalLinks;
2+
3+
public class LocalLinkMigrationTracker
4+
{
5+
public bool HasFixedMigrationRun { get; private set; }
6+
7+
public void MarkFixedMigrationRan() => HasFixedMigrationRun = true;
8+
}

src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/LocalLinks/LocalLinkProcessor.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ public string ProcessStringValue(string input)
4343
string newTagHref;
4444
if (tag.Udi is not null)
4545
{
46-
newTagHref = $" type=\"{tag.Udi.EntityType}\" "
47-
+ tag.TagHref.Replace(tag.Udi.ToString(), tag.Udi.Guid.ToString());
46+
newTagHref = tag.TagHref.Replace(tag.Udi.ToString(), tag.Udi.Guid.ToString())
47+
+ $"\" type=\"{tag.Udi.EntityType}";
4848
}
4949
else if (tag.IntId is not null)
5050
{
@@ -55,8 +55,8 @@ public string ProcessStringValue(string input)
5555
continue;
5656
}
5757

58-
newTagHref = $" type=\"{conversionResult.Value.EntityType}\" "
59-
+ tag.TagHref.Replace(tag.IntId.Value.ToString(), conversionResult.Value.Key.ToString());
58+
newTagHref = tag.TagHref.Replace(tag.IntId.Value.ToString(), conversionResult.Value.Key.ToString())
59+
+ $"\" type=\"{conversionResult.Value.EntityType}";
6060
}
6161
else
6262
{
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System.Text.RegularExpressions;
2+
using Umbraco.Cms.Core;
3+
using Umbraco.Cms.Core.Models;
4+
using Umbraco.Cms.Core.Services;
5+
6+
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0.LocalLinks;
7+
8+
[Obsolete("Will be removed in V18")]
9+
public class LocalLinkProcessorForFaultyLinks
10+
{
11+
private readonly IIdKeyMap _idKeyMap;
12+
private readonly IEnumerable<ITypedLocalLinkProcessor> _localLinkProcessors;
13+
private const string LocalLinkLocation = "__LOCALLINKLOCATION__";
14+
private const string TypeAttributeLocation = "__TYPEATTRIBUTELOCATION__";
15+
16+
internal static readonly Regex FaultyHrefPattern = new(
17+
@"<a (?<faultyHref>href=['""] ?(?<typeAttribute> type=*?['""][^'""]*?['""] )?(?<localLink>\/{localLink:[a-fA-F0-9-]+}['""])).*?>",
18+
RegexOptions.IgnoreCase | RegexOptions.Singleline);
19+
20+
public LocalLinkProcessorForFaultyLinks(
21+
IIdKeyMap idKeyMap,
22+
IEnumerable<ITypedLocalLinkProcessor> localLinkProcessors)
23+
{
24+
_idKeyMap = idKeyMap;
25+
_localLinkProcessors = localLinkProcessors;
26+
}
27+
28+
public IEnumerable<string> GetSupportedPropertyEditorAliases() =>
29+
_localLinkProcessors.SelectMany(p => p.PropertyEditorAliases);
30+
31+
public bool ProcessToEditorValue(object? editorValue)
32+
{
33+
ITypedLocalLinkProcessor? processor =
34+
_localLinkProcessors.FirstOrDefault(p => p.PropertyEditorValueType == editorValue?.GetType());
35+
36+
return processor is not null && processor.Process.Invoke(editorValue, ProcessToEditorValue, ProcessStringValue);
37+
}
38+
39+
public string ProcessStringValue(string input)
40+
{
41+
MatchCollection faultyTags = FaultyHrefPattern.Matches(input);
42+
43+
foreach (Match fullTag in faultyTags)
44+
{
45+
var newValue =
46+
fullTag.Value.Replace(fullTag.Groups["typeAttribute"].Value, LocalLinkLocation)
47+
.Replace(fullTag.Groups["localLink"].Value, TypeAttributeLocation)
48+
.Replace(LocalLinkLocation, fullTag.Groups["localLink"].Value)
49+
.Replace(TypeAttributeLocation, fullTag.Groups["typeAttribute"].Value);
50+
input = input.Replace(fullTag.Value, newValue);
51+
}
52+
53+
return input;
54+
}
55+
56+
private (Guid Key, string EntityType)? CreateIntBasedKeyType(int id)
57+
{
58+
// very old data, best effort replacement
59+
Attempt<Guid> documentAttempt = _idKeyMap.GetKeyForId(id, UmbracoObjectTypes.Document);
60+
if (documentAttempt.Success)
61+
{
62+
return (Key: documentAttempt.Result, EntityType: UmbracoObjectTypes.Document.ToString());
63+
}
64+
65+
Attempt<Guid> mediaAttempt = _idKeyMap.GetKeyForId(id, UmbracoObjectTypes.Media);
66+
if (mediaAttempt.Success)
67+
{
68+
return (Key: mediaAttempt.Result, EntityType: UmbracoObjectTypes.Media.ToString());
69+
}
70+
71+
return null;
72+
}
73+
}

src/Umbraco.Infrastructure/Migrations/Upgrade/V_15_0_0/LocalLinks/LocalLinkRteProcessor.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Text.RegularExpressions;
12
using Umbraco.Cms.Core;
23
using Umbraco.Cms.Core.Models.Blocks;
34

@@ -28,6 +29,16 @@ public bool ProcessRichText(
2829
bool hasChanged = false;
2930

3031
var newMarkup = processStringValue.Invoke(richTextValue.Markup);
32+
33+
// fix recursive hickup in ConvertRichTextEditorProperties
34+
newMarkup = RteBlockHelper.BlockRegex().Replace(
35+
newMarkup,
36+
match => UdiParser.TryParse(match.Groups["udi"].Value, out GuidUdi? guidUdi)
37+
? match.Value
38+
.Replace(match.Groups["attribute"].Value, "data-content-key")
39+
.Replace(match.Groups["udi"].Value, guidUdi.Guid.ToString("D"))
40+
: string.Empty);
41+
3142
if (newMarkup.Equals(richTextValue.Markup) == false)
3243
{
3344
hasChanged = true;
@@ -53,3 +64,10 @@ public bool ProcessRichText(
5364
return hasChanged;
5465
}
5566
}
67+
68+
[Obsolete("Will be removed in V18")]
69+
public static partial class RteBlockHelper
70+
{
71+
[GeneratedRegex("<umb-rte-block.*(?<attribute>data-content-udi)=\"(?<udi>.[^\"]*)\".*<\\/umb-rte-block")]
72+
public static partial Regex BlockRegex();
73+
}

0 commit comments

Comments
 (0)