From e6568c69dc13fd1a23fce4355d5f72fa18f2e7b6 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Fri, 31 May 2024 12:26:37 +0200 Subject: [PATCH] Added a notifiction handler that checks if we wanna have domain publish warnings. If so it adds as Umb-Notifications and logs it. (#16507) --- ...rningsWhenPublishingNotificationHandler.cs | 126 ++++++++++++++++++ .../UmbracoBuilder.CoreServices.cs | 4 + 2 files changed, 130 insertions(+) create mode 100644 src/Umbraco.Core/Events/AddDomainWarningsWhenPublishingNotificationHandler.cs diff --git a/src/Umbraco.Core/Events/AddDomainWarningsWhenPublishingNotificationHandler.cs b/src/Umbraco.Core/Events/AddDomainWarningsWhenPublishingNotificationHandler.cs new file mode 100644 index 0000000000..ab9244bfc0 --- /dev/null +++ b/src/Umbraco.Core/Events/AddDomainWarningsWhenPublishingNotificationHandler.cs @@ -0,0 +1,126 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Notifications; +using Umbraco.Cms.Core.Services; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Core.Events; + +public class AddDomainWarningsWhenPublishingNotificationHandler : INotificationHandler +{ + private readonly IOptions _contentSettings; + private readonly IContentService _contentService; + private readonly IDomainService _domainService; + private readonly IEventMessagesFactory _eventMessagesFactory; + private readonly ILogger _logger; + + public AddDomainWarningsWhenPublishingNotificationHandler( + IOptions contentSettings, + IContentService contentService, + IDomainService domainService, + IEventMessagesFactory eventMessagesFactory, + ILogger logger) + { + _contentSettings = contentSettings; + _contentService = contentService; + _domainService = domainService; + _eventMessagesFactory = eventMessagesFactory; + _logger = logger; + } + + public void Handle(ContentPublishedNotification notification) + { + if (_contentSettings.Value.ShowDomainWarnings is false) + { + return; + } + + + foreach (IContent content in notification.PublishedEntities) + { + + var publishedCultures = GetPublishedCulturesFromAncestors(content).ToList(); + // If only a single culture is published we shouldn't have any routing issues + if (publishedCultures.Count < 2) + { + return; + } + + // If more than a single culture is published we need to verify that there's a domain registered for each published culture + HashSet? assignedDomains = content is null + ? null + : _domainService.GetAssignedDomains(content.Id, true)?.ToHashSet(); + + IEnumerable? ancestorIds = content?.GetAncestorIds(); + if (ancestorIds is not null && assignedDomains is not null) + { + // We also have to check all of the ancestors, if any of those has the appropriate culture assigned we don't need to warn + foreach (var ancestorID in ancestorIds) + { + assignedDomains.UnionWith(_domainService.GetAssignedDomains(ancestorID, true) ?? + Enumerable.Empty()); + } + } + + var eventMessages = _eventMessagesFactory.Get(); + // No domains at all, add a warning, to add domains. + if (assignedDomains is null || assignedDomains.Count == 0) + { + + eventMessages.Add(new EventMessage("Content published", $"Domains are not configured for multilingual site, please contact an administrator, see log for more information", EventMessageType.Warning)); + + _logger.LogWarning( + "The root node {RootNodeName} was published with multiple cultures, but no domains are configured, this will cause routing and caching issues, please register domains for: {Cultures}", + content?.Name, + string.Join(", ", publishedCultures)); + return; + + } + + // If there is some domains, verify that there's a domain for each of the published cultures + foreach (var culture in publishedCultures + .Where(culture => assignedDomains.Any(x => + x.LanguageIsoCode?.Equals(culture, StringComparison.OrdinalIgnoreCase) ?? false) is false)) + { + eventMessages.Add(new EventMessage("Content published", $"There is no domain configured for '{culture}', please contact an administrator, see\\n log for more information", EventMessageType.Warning)); + + + _logger.LogWarning( + "The root node {RootNodeName} was published in culture {Culture}, but there's no domain configured for it, this will cause routing and caching issues, please register a domain for it", + content?.Name, + culture); + } + } + } + + private IEnumerable GetPublishedCulturesFromAncestors(IContent? content) + { + if (content?.ParentId is not -1 && content?.HasIdentity is false) + { + content = _contentService.GetById(content.ParentId); + } + + if (content?.ParentId == -1) + { + return content.PublishedCultures; + } + + HashSet publishedCultures = new(); + publishedCultures.UnionWith(content?.PublishedCultures ?? Enumerable.Empty()); + + IEnumerable? ancestorIds = content?.GetAncestorIds(); + + if (ancestorIds is not null) + { + foreach (var id in ancestorIds) + { + IEnumerable? cultures = _contentService.GetById(id)?.PublishedCultures; + publishedCultures.UnionWith(cultures ?? Enumerable.Empty()); + } + } + + return publishedCultures; + } +} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs index b2b38dd3c7..47ff6f2489 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.CoreServices.cs @@ -400,6 +400,10 @@ public static partial class UmbracoBuilderExtensions .AddNotificationHandler() .AddNotificationHandler(); + // Handlers for publish warnings + builder + .AddNotificationHandler(); + return builder; }