Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/Umbraco.Core/Cache/DistributedCacheExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ public static void RefreshContentCache(this DistributedCache dc, IEnumerable<Tre
Id = x.Item.Id,
Key = x.Item.Key,
ChangeTypes = x.ChangeTypes,
Blueprint = x.Item.Blueprint
Blueprint = x.Item.Blueprint,
PublishedCultures = x.PublishedCultures?.ToArray(),
UnpublishedCultures = x.UnpublishedCultures?.ToArray()
});

dc.RefreshByPayload(ContentCacheRefresher.UniqueId, payloads);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ public JsonPayload(int id, Guid? key, TreeChangeTypes changeTypes)
public TreeChangeTypes ChangeTypes { get; init; }

public bool Blueprint { get; init; }

public string[]? PublishedCultures { get; init; }

public string[]? UnpublishedCultures { get; init; }
}

#endregion
Expand Down
10 changes: 10 additions & 0 deletions src/Umbraco.Core/Notifications/ContentTreeChangeNotification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,14 @@ public ContentTreeChangeNotification(
: base(new TreeChange<IContent>(target, changeTypes), messages)
{
}

public ContentTreeChangeNotification(
IContent target,
TreeChangeTypes changeTypes,
IEnumerable<string>? publishedCultures,
IEnumerable<string>? unpublishedCultures,
EventMessages messages)
: base(new TreeChange<IContent>(target, changeTypes, publishedCultures, unpublishedCultures), messages)
{
}
}
12 changes: 12 additions & 0 deletions src/Umbraco.Core/Services/Changes/TreeChange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,22 @@ public TreeChange(TItem changedItem, TreeChangeTypes changeTypes)
ChangeTypes = changeTypes;
}

public TreeChange(TItem changedItem, TreeChangeTypes changeTypes, IEnumerable<string>? publishedCultures, IEnumerable<string>? unpublishedCultures)
{
Item = changedItem;
ChangeTypes = changeTypes;
PublishedCultures = publishedCultures;
UnpublishedCultures = unpublishedCultures;
}

public TItem Item { get; }

public TreeChangeTypes ChangeTypes { get; }

public IEnumerable<string>? PublishedCultures { get; }

public IEnumerable<string>? UnpublishedCultures { get; }

public EventArgs ToEventArgs() => new EventArgs(this);

public class EventArgs : System.EventArgs
Expand Down
34 changes: 27 additions & 7 deletions src/Umbraco.Core/Services/ContentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,12 @@ void SaveDocument(IContent c)
// events and audit
scope.Notifications.Publish(
new ContentUnpublishedNotification(content, eventMessages).WithState(notificationState));
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshBranch, eventMessages));
scope.Notifications.Publish(new ContentTreeChangeNotification(
content,
TreeChangeTypes.RefreshBranch,
variesByCulture ? culturesPublishing.IsCollectionEmpty() ? null : culturesPublishing : null,
variesByCulture ? culturesUnpublishing.IsCollectionEmpty() ? null : culturesUnpublishing : ["*"],
eventMessages));

if (culturesUnpublishing != null)
{
Expand Down Expand Up @@ -1654,7 +1659,12 @@ void SaveDocument(IContent c)
if (!branchOne)
{
scope.Notifications.Publish(
new ContentTreeChangeNotification(content, changeType, eventMessages));
new ContentTreeChangeNotification(
content,
changeType,
variesByCulture ? culturesPublishing.IsCollectionEmpty() ? null : culturesPublishing : ["*"],
variesByCulture ? culturesUnpublishing.IsCollectionEmpty() ? null : culturesUnpublishing : null,
eventMessages));
scope.Notifications.Publish(
new ContentPublishedNotification(content, eventMessages).WithState(notificationState));
}
Expand Down Expand Up @@ -2118,7 +2128,8 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
}

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

HashSet<string> culturesPublished = culturesToPublish ?? [];

// deal with descendants
// if one fails, abort its branch
var exclude = new HashSet<int>();
Expand All @@ -2153,12 +2166,14 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
}

// no need to check path here, parent has to be published here
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs, out _);
culturesToPublish = shouldPublish(d);
result = SaveAndPublishBranchItem(scope, d, culturesToPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs, out _);
if (result != null)
{
results.Add(result);
if (result.Success)
{
culturesPublished.UnionWith(culturesToPublish ?? []);
continue;
}
}
Expand All @@ -2175,8 +2190,14 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(

// trigger events for the entire branch
// (SaveAndPublishBranchOne does *not* do it)
var variesByCulture = document.ContentType.VariesByCulture();
scope.Notifications.Publish(
new ContentTreeChangeNotification(document, TreeChangeTypes.RefreshBranch, eventMessages));
new ContentTreeChangeNotification(
document,
TreeChangeTypes.RefreshBranch,
variesByCulture ? culturesPublished.IsCollectionEmpty() ? null : culturesPublished : ["*"],
null,
eventMessages));
scope.Notifications.Publish(new ContentPublishedNotification(publishedDocuments, eventMessages).WithState(notificationState));

scope.Complete();
Expand All @@ -2191,7 +2212,7 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
private PublishResult? SaveAndPublishBranchItem(
ICoreScope scope,
IContent document,
Func<IContent, HashSet<string>?> shouldPublish,
HashSet<string>? culturesToPublish,
Func<IContent, HashSet<string>, IReadOnlyCollection<ILanguage>,
bool> publishCultures,
bool isRoot,
Expand All @@ -2202,7 +2223,6 @@ internal IEnumerable<PublishResult> SaveAndPublishBranch(
out IDictionary<string, object?> notificationState)
{
notificationState = new Dictionary<string, object?>();
HashSet<string>? culturesToPublish = shouldPublish(document);

// null = do not include
if (culturesToPublish == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ protected override void CustomTestSetup(IUmbracoBuilder builder) => builder
.AddNotificationHandler<ContentPublishingNotification, ContentNotificationHandler>()
.AddNotificationHandler<ContentPublishedNotification, ContentNotificationHandler>()
.AddNotificationHandler<ContentUnpublishingNotification, ContentNotificationHandler>()
.AddNotificationHandler<ContentUnpublishedNotification, ContentNotificationHandler>();
.AddNotificationHandler<ContentUnpublishedNotification, ContentNotificationHandler>()
.AddNotificationHandler<ContentTreeChangeNotification, ContentNotificationHandler>();

private void CreateTestData()
{
Expand Down Expand Up @@ -177,6 +178,67 @@ public void Saving_Set_Value()
}
}

[Test]
public void Publishing_Invariant()
{
IContent document = new Content("content", -1, _contentType);

var treeChangeWasCalled = false;

ContentNotificationHandler.TreeChange += notification =>
{
var change = notification.Changes.FirstOrDefault();
var publishedCultures = change?.PublishedCultures?.ToArray();
Assert.IsNotNull(publishedCultures);
Assert.AreEqual(1, publishedCultures.Length);
Assert.IsTrue(publishedCultures.InvariantContains("*"));
Assert.IsNull(change.UnpublishedCultures);

treeChangeWasCalled = true;
};

try
{
ContentService.SaveAndPublish(document);
Assert.IsTrue(treeChangeWasCalled);
}
finally
{
ContentNotificationHandler.TreeChange = null;
}
}

[Test]
public void Unpublishing_Invariant()
{
IContent document = new Content("content", -1, _contentType);
ContentService.SaveAndPublish(document);

var treeChangeWasCalled = false;

ContentNotificationHandler.TreeChange += notification =>
{
var change = notification.Changes.FirstOrDefault();
Assert.IsNull(change?.PublishedCultures);
var unpublishedCultures = change?.UnpublishedCultures?.ToArray();
Assert.IsNotNull(unpublishedCultures);
Assert.AreEqual(1, unpublishedCultures.Length);
Assert.IsTrue(unpublishedCultures.InvariantContains("*"));

treeChangeWasCalled = true;
};

try
{
ContentService.Unpublish(document);
Assert.IsTrue(treeChangeWasCalled);
}
finally
{
ContentNotificationHandler.TreeChange = null;
}
}

[Test]
public void Publishing_Culture()
{
Expand All @@ -203,6 +265,7 @@ public void Publishing_Culture()

var publishingWasCalled = false;
var publishedWasCalled = false;
var treeChangeWasCalled = false;

ContentNotificationHandler.PublishingContent += notification =>
{
Expand All @@ -228,16 +291,30 @@ public void Publishing_Culture()
publishedWasCalled = true;
};

ContentNotificationHandler.TreeChange += notification =>
{
var change = notification.Changes.FirstOrDefault();
var publishedCultures = change?.PublishedCultures?.ToArray();
Assert.IsNotNull(publishedCultures);
Assert.AreEqual(1, publishedCultures.Length);
Assert.IsTrue(publishedCultures.InvariantContains("fr-FR"));
Assert.IsNull(change.UnpublishedCultures);

treeChangeWasCalled = true;
};

try
{
ContentService.SaveAndPublish(document, "fr-FR");
Assert.IsTrue(publishingWasCalled);
Assert.IsTrue(publishedWasCalled);
Assert.IsTrue(treeChangeWasCalled);
}
finally
{
ContentNotificationHandler.PublishingContent = null;
ContentNotificationHandler.PublishedContent = null;
ContentNotificationHandler.TreeChange = null;
}

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

var publishingWasCalled = false;
var publishedWasCalled = false;
var treeChangeWasCalled = false;

// 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?

Expand Down Expand Up @@ -399,16 +477,30 @@ public void Unpublishing_Culture()
publishedWasCalled = true;
};

ContentNotificationHandler.TreeChange += notification =>
{
var change = notification.Changes.FirstOrDefault();
var unpublishedCultures = change?.UnpublishedCultures?.ToArray();
Assert.IsNotNull(unpublishedCultures);
Assert.AreEqual(1, unpublishedCultures.Length);
Assert.IsTrue(unpublishedCultures.InvariantContains("fr-FR"));
Assert.IsNull(change.PublishedCultures);

treeChangeWasCalled = true;
};

try
{
ContentService.CommitDocumentChanges(document);
Assert.IsTrue(publishingWasCalled);
Assert.IsTrue(publishedWasCalled);
Assert.IsTrue(treeChangeWasCalled);
}
finally
{
ContentNotificationHandler.PublishingContent = null;
ContentNotificationHandler.PublishedContent = null;
ContentNotificationHandler.TreeChange = null;
}

document = ContentService.GetById(document.Id);
Expand All @@ -423,7 +515,8 @@ public class ContentNotificationHandler :
INotificationHandler<ContentPublishingNotification>,
INotificationHandler<ContentPublishedNotification>,
INotificationHandler<ContentUnpublishingNotification>,
INotificationHandler<ContentUnpublishedNotification>
INotificationHandler<ContentUnpublishedNotification>,
INotificationHandler<ContentTreeChangeNotification>
{
public static Action<ContentSavingNotification> SavingContent { get; set; }

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

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

public static Action<ContentTreeChangeNotification> TreeChange { get; set; }

public void Handle(ContentPublishedNotification notification) => PublishedContent?.Invoke(notification);

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

public void Handle(ContentUnpublishingNotification notification) => UnpublishingContent?.Invoke(notification);

public void Handle(ContentTreeChangeNotification notification) => TreeChange?.Invoke(notification);
}
}
Loading