Skip to content

Commit 16749a7

Browse files
kjacZeegaan
authored andcommitted
Add (un)publishing details to TreeChange notifications (#17757)
(cherry picked from commit 404a62a)
1 parent a627930 commit 16749a7

File tree

7 files changed

+204
-17
lines changed

7 files changed

+204
-17
lines changed

src/Umbraco.Core/Cache/DistributedCacheExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ public static void RefreshContentCache(this DistributedCache dc, IEnumerable<Tre
142142
Id = x.Item.Id,
143143
Key = x.Item.Key,
144144
ChangeTypes = x.ChangeTypes,
145-
Blueprint = x.Item.Blueprint
145+
Blueprint = x.Item.Blueprint,
146+
PublishedCultures = x.PublishedCultures?.ToArray(),
147+
UnpublishedCultures = x.UnpublishedCultures?.ToArray()
146148
});
147149

148150
dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);

src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ public JsonPayload(int id, Guid? key, TreeChangeTypes changeTypes)
182182
public TreeChangeTypes ChangeTypes { get; init; }
183183

184184
public bool Blueprint { get; init; }
185+
186+
public string[]? PublishedCultures { get; init; }
187+
188+
public string[]? UnpublishedCultures { get; init; }
185189
}
186190

187191
#endregion

src/Umbraco.Core/Notifications/ContentTreeChangeNotification.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,14 @@ public ContentTreeChangeNotification(
3232
: base(new TreeChange<IContent>(target, changeTypes), messages)
3333
{
3434
}
35+
36+
public ContentTreeChangeNotification(
37+
IContent target,
38+
TreeChangeTypes changeTypes,
39+
IEnumerable<string>? publishedCultures,
40+
IEnumerable<string>? unpublishedCultures,
41+
EventMessages messages)
42+
: base(new TreeChange<IContent>(target, changeTypes, publishedCultures, unpublishedCultures), messages)
43+
{
44+
}
3545
}

src/Umbraco.Core/Services/Changes/TreeChange.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,22 @@ public TreeChange(TItem changedItem, TreeChangeTypes changeTypes)
88
ChangeTypes = changeTypes;
99
}
1010

11+
public TreeChange(TItem changedItem, TreeChangeTypes changeTypes, IEnumerable<string>? publishedCultures, IEnumerable<string>? unpublishedCultures)
12+
{
13+
Item = changedItem;
14+
ChangeTypes = changeTypes;
15+
PublishedCultures = publishedCultures;
16+
UnpublishedCultures = unpublishedCultures;
17+
}
18+
1119
public TItem Item { get; }
1220

1321
public TreeChangeTypes ChangeTypes { get; }
1422

23+
public IEnumerable<string>? PublishedCultures { get; }
24+
25+
public IEnumerable<string>? UnpublishedCultures { get; }
26+
1527
public EventArgs ToEventArgs() => new EventArgs(this);
1628

1729
public class EventArgs : System.EventArgs

src/Umbraco.Core/Services/ContentService.cs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,12 @@ void SaveDocument(IContent c)
15951595
// events and audit
15961596
scope.Notifications.Publish(
15971597
new ContentUnpublishedNotification(content, eventMessages).WithState(notificationState));
1598-
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshBranch, eventMessages));
1598+
scope.Notifications.Publish(new ContentTreeChangeNotification(
1599+
content,
1600+
TreeChangeTypes.RefreshBranch,
1601+
variesByCulture ? culturesPublishing.IsCollectionEmpty() ? null : culturesPublishing : null,
1602+
variesByCulture ? culturesUnpublishing.IsCollectionEmpty() ? null : culturesUnpublishing : ["*"],
1603+
eventMessages));
15991604

16001605
if (culturesUnpublishing != null)
16011606
{
@@ -1654,7 +1659,12 @@ void SaveDocument(IContent c)
16541659
if (!branchOne)
16551660
{
16561661
scope.Notifications.Publish(
1657-
new ContentTreeChangeNotification(content, changeType, eventMessages));
1662+
new ContentTreeChangeNotification(
1663+
content,
1664+
changeType,
1665+
variesByCulture ? culturesPublishing.IsCollectionEmpty() ? null : culturesPublishing : ["*"],
1666+
variesByCulture ? culturesUnpublishing.IsCollectionEmpty() ? null : culturesUnpublishing : null,
1667+
eventMessages));
16581668
scope.Notifications.Publish(
16591669
new ContentPublishedNotification(content, eventMessages).WithState(notificationState));
16601670
}
@@ -2118,7 +2128,8 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
21182128
}
21192129

21202130
// deal with the branch root - if it fails, abort
2121-
PublishResult? result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, eventMessages, userId, allLangs, out IDictionary<string, object?> notificationState);
2131+
HashSet<string>? culturesToPublish = shouldPublish(document);
2132+
PublishResult? result = SaveAndPublishBranchItem(scope, document, culturesToPublish, publishCultures, true, publishedDocuments, eventMessages, userId, allLangs, out IDictionary<string, object?> notificationState);
21222133
if (result != null)
21232134
{
21242135
results.Add(result);
@@ -2128,6 +2139,8 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
21282139
}
21292140
}
21302141

2142+
HashSet<string> culturesPublished = culturesToPublish ?? [];
2143+
21312144
// deal with descendants
21322145
// if one fails, abort its branch
21332146
var exclude = new HashSet<int>();
@@ -2153,12 +2166,14 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
21532166
}
21542167

21552168
// no need to check path here, parent has to be published here
2156-
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs, out _);
2169+
culturesToPublish = shouldPublish(d);
2170+
result = SaveAndPublishBranchItem(scope, d, culturesToPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs, out _);
21572171
if (result != null)
21582172
{
21592173
results.Add(result);
21602174
if (result.Success)
21612175
{
2176+
culturesPublished.UnionWith(culturesToPublish ?? []);
21622177
continue;
21632178
}
21642179
}
@@ -2175,8 +2190,14 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
21752190

21762191
// trigger events for the entire branch
21772192
// (SaveAndPublishBranchOne does *not* do it)
2193+
var variesByCulture = document.ContentType.VariesByCulture();
21782194
scope.Notifications.Publish(
2179-
new ContentTreeChangeNotification(document, TreeChangeTypes.RefreshBranch, eventMessages));
2195+
new ContentTreeChangeNotification(
2196+
document,
2197+
TreeChangeTypes.RefreshBranch,
2198+
variesByCulture ? culturesPublished.IsCollectionEmpty() ? null : culturesPublished : ["*"],
2199+
null,
2200+
eventMessages));
21802201
scope.Notifications.Publish(new ContentPublishedNotification(publishedDocuments, eventMessages).WithState(notificationState));
21812202

21822203
scope.Complete();
@@ -2191,7 +2212,7 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
21912212
private PublishResult? SaveAndPublishBranchItem(
21922213
ICoreScope scope,
21932214
IContent document,
2194-
Func<IContent, HashSet<string>?> shouldPublish,
2215+
HashSet<string>? culturesToPublish,
21952216
Func<IContent, HashSet<string>, IReadOnlyCollection<ILanguage>,
21962217
bool> publishCultures,
21972218
bool isRoot,
@@ -2202,7 +2223,6 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
22022223
out IDictionary<string, object?> notificationState)
22032224
{
22042225
notificationState = new Dictionary<string, object?>();
2205-
HashSet<string>? culturesToPublish = shouldPublish(document);
22062226

22072227
// null = do not include
22082228
if (culturesToPublish == null)

tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceNotificationTests.cs

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ protected override void CustomTestSetup(IUmbracoBuilder builder) => builder
5555
.AddNotificationHandler<ContentPublishingNotification, ContentNotificationHandler>()
5656
.AddNotificationHandler<ContentPublishedNotification, ContentNotificationHandler>()
5757
.AddNotificationHandler<ContentUnpublishingNotification, ContentNotificationHandler>()
58-
.AddNotificationHandler<ContentUnpublishedNotification, ContentNotificationHandler>();
58+
.AddNotificationHandler<ContentUnpublishedNotification, ContentNotificationHandler>()
59+
.AddNotificationHandler<ContentTreeChangeNotification, ContentNotificationHandler>();
5960

6061
private void CreateTestData()
6162
{
@@ -177,6 +178,67 @@ public void Saving_Set_Value()
177178
}
178179
}
179180

181+
[Test]
182+
public void Publishing_Invariant()
183+
{
184+
IContent document = new Content("content", -1, _contentType);
185+
186+
var treeChangeWasCalled = false;
187+
188+
ContentNotificationHandler.TreeChange += notification =>
189+
{
190+
var change = notification.Changes.FirstOrDefault();
191+
var publishedCultures = change?.PublishedCultures?.ToArray();
192+
Assert.IsNotNull(publishedCultures);
193+
Assert.AreEqual(1, publishedCultures.Length);
194+
Assert.IsTrue(publishedCultures.InvariantContains("*"));
195+
Assert.IsNull(change.UnpublishedCultures);
196+
197+
treeChangeWasCalled = true;
198+
};
199+
200+
try
201+
{
202+
ContentService.SaveAndPublish(document);
203+
Assert.IsTrue(treeChangeWasCalled);
204+
}
205+
finally
206+
{
207+
ContentNotificationHandler.TreeChange = null;
208+
}
209+
}
210+
211+
[Test]
212+
public void Unpublishing_Invariant()
213+
{
214+
IContent document = new Content("content", -1, _contentType);
215+
ContentService.SaveAndPublish(document);
216+
217+
var treeChangeWasCalled = false;
218+
219+
ContentNotificationHandler.TreeChange += notification =>
220+
{
221+
var change = notification.Changes.FirstOrDefault();
222+
Assert.IsNull(change?.PublishedCultures);
223+
var unpublishedCultures = change?.UnpublishedCultures?.ToArray();
224+
Assert.IsNotNull(unpublishedCultures);
225+
Assert.AreEqual(1, unpublishedCultures.Length);
226+
Assert.IsTrue(unpublishedCultures.InvariantContains("*"));
227+
228+
treeChangeWasCalled = true;
229+
};
230+
231+
try
232+
{
233+
ContentService.Unpublish(document);
234+
Assert.IsTrue(treeChangeWasCalled);
235+
}
236+
finally
237+
{
238+
ContentNotificationHandler.TreeChange = null;
239+
}
240+
}
241+
180242
[Test]
181243
public void Publishing_Culture()
182244
{
@@ -203,6 +265,7 @@ public void Publishing_Culture()
203265

204266
var publishingWasCalled = false;
205267
var publishedWasCalled = false;
268+
var treeChangeWasCalled = false;
206269

207270
ContentNotificationHandler.PublishingContent += notification =>
208271
{
@@ -228,16 +291,30 @@ public void Publishing_Culture()
228291
publishedWasCalled = true;
229292
};
230293

294+
ContentNotificationHandler.TreeChange += notification =>
295+
{
296+
var change = notification.Changes.FirstOrDefault();
297+
var publishedCultures = change?.PublishedCultures?.ToArray();
298+
Assert.IsNotNull(publishedCultures);
299+
Assert.AreEqual(1, publishedCultures.Length);
300+
Assert.IsTrue(publishedCultures.InvariantContains("fr-FR"));
301+
Assert.IsNull(change.UnpublishedCultures);
302+
303+
treeChangeWasCalled = true;
304+
};
305+
231306
try
232307
{
233308
ContentService.SaveAndPublish(document, "fr-FR");
234309
Assert.IsTrue(publishingWasCalled);
235310
Assert.IsTrue(publishedWasCalled);
311+
Assert.IsTrue(treeChangeWasCalled);
236312
}
237313
finally
238314
{
239315
ContentNotificationHandler.PublishingContent = null;
240316
ContentNotificationHandler.PublishedContent = null;
317+
ContentNotificationHandler.TreeChange = null;
241318
}
242319

243320
document = ContentService.GetById(document.Id);
@@ -366,6 +443,7 @@ public void Unpublishing_Culture()
366443

367444
var publishingWasCalled = false;
368445
var publishedWasCalled = false;
446+
var treeChangeWasCalled = false;
369447

370448
// TODO: revisit this - it was migrated when removing static events, but the expected result seems illogic - why does this test bind to Published and not Unpublished?
371449

@@ -399,16 +477,30 @@ public void Unpublishing_Culture()
399477
publishedWasCalled = true;
400478
};
401479

480+
ContentNotificationHandler.TreeChange += notification =>
481+
{
482+
var change = notification.Changes.FirstOrDefault();
483+
var unpublishedCultures = change?.UnpublishedCultures?.ToArray();
484+
Assert.IsNotNull(unpublishedCultures);
485+
Assert.AreEqual(1, unpublishedCultures.Length);
486+
Assert.IsTrue(unpublishedCultures.InvariantContains("fr-FR"));
487+
Assert.IsNull(change.PublishedCultures);
488+
489+
treeChangeWasCalled = true;
490+
};
491+
402492
try
403493
{
404494
ContentService.CommitDocumentChanges(document);
405495
Assert.IsTrue(publishingWasCalled);
406496
Assert.IsTrue(publishedWasCalled);
497+
Assert.IsTrue(treeChangeWasCalled);
407498
}
408499
finally
409500
{
410501
ContentNotificationHandler.PublishingContent = null;
411502
ContentNotificationHandler.PublishedContent = null;
503+
ContentNotificationHandler.TreeChange = null;
412504
}
413505

414506
document = ContentService.GetById(document.Id);
@@ -423,7 +515,8 @@ public class ContentNotificationHandler :
423515
INotificationHandler<ContentPublishingNotification>,
424516
INotificationHandler<ContentPublishedNotification>,
425517
INotificationHandler<ContentUnpublishingNotification>,
426-
INotificationHandler<ContentUnpublishedNotification>
518+
INotificationHandler<ContentUnpublishedNotification>,
519+
INotificationHandler<ContentTreeChangeNotification>
427520
{
428521
public static Action<ContentSavingNotification> SavingContent { get; set; }
429522

@@ -437,6 +530,8 @@ public class ContentNotificationHandler :
437530

438531
public static Action<ContentUnpublishedNotification> UnpublishedContent { get; set; }
439532

533+
public static Action<ContentTreeChangeNotification> TreeChange { get; set; }
534+
440535
public void Handle(ContentPublishedNotification notification) => PublishedContent?.Invoke(notification);
441536

442537
public void Handle(ContentPublishingNotification notification) => PublishingContent?.Invoke(notification);
@@ -447,5 +542,7 @@ public class ContentNotificationHandler :
447542
public void Handle(ContentUnpublishedNotification notification) => UnpublishedContent?.Invoke(notification);
448543

449544
public void Handle(ContentUnpublishingNotification notification) => UnpublishingContent?.Invoke(notification);
545+
546+
public void Handle(ContentTreeChangeNotification notification) => TreeChange?.Invoke(notification);
450547
}
451548
}

0 commit comments

Comments
 (0)