Skip to content
Open
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
2 changes: 2 additions & 0 deletions src/Umbraco.Cms.Search.Core/Configuration/IndexOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public sealed class IndexOptions
{
private readonly Dictionary<string, IndexRegistration> _register = [];

public required string[] IncludeRebuildWhenLanguageDeleted { get; set; } = [Constants.IndexAliases.DraftContent, Constants.IndexAliases.PublishedContent];

public void RegisterIndex<TIndexer, TSearcher, TContentChangeStrategy>(string indexAlias, params UmbracoObjectTypes[] containedObjectTypes)
where TIndexer : class, IIndexer
where TSearcher : class, ISearcher
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Search.Core.Configuration;
using Umbraco.Cms.Search.Core.Services.ContentIndexing;

namespace Umbraco.Cms.Search.Core.NotificationHandlers;

internal sealed class RebuildIndexesNotificationHandler : INotificationHandler<UmbracoApplicationStartedNotification>
internal sealed class RebuildIndexesNotificationHandler : INotificationHandler<UmbracoApplicationStartedNotification>, INotificationHandler<LanguageDeletedNotification>
{
private readonly IContentIndexingService _contentIndexingService;
private readonly ILogger<RebuildIndexesNotificationHandler> _logger;
private readonly IndexOptions _options;

public RebuildIndexesNotificationHandler(
IContentIndexingService contentIndexingService,
ILogger<RebuildIndexesNotificationHandler> logger)
ILogger<RebuildIndexesNotificationHandler> logger,
IOptions<IndexOptions> options)
{
_contentIndexingService = contentIndexingService;
_logger = logger;
_options = options.Value;
}

public void Handle(UmbracoApplicationStartedNotification notification)
Expand All @@ -26,4 +31,14 @@ public void Handle(UmbracoApplicationStartedNotification notification)
_contentIndexingService.Rebuild(Constants.IndexAliases.DraftMedia);
_contentIndexingService.Rebuild(Constants.IndexAliases.DraftMembers);
}

public void Handle(LanguageDeletedNotification notification)
{
_logger.LogInformation("Rebuilding search indexes after language deletion...");

foreach (var indexAlias in _options.IncludeRebuildWhenLanguageDeleted)
{
_contentIndexingService.Rebuild(indexAlias);
}
}
}
3 changes: 3 additions & 0 deletions src/Umbraco.Cms.Search.Core/Umbraco.Cms.Search.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Umbraco.Test.Search.Unit</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Umbraco.Test.Search.Examine.Integration</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
</AssemblyAttribute>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ public async Task CreateVariantDocumentTree()
.WithCultureInfo("ja-JP")
.Build();

LocalizationService.Save(langDk);
LocalizationService.Save(langJp);
await LanguageService.CreateAsync(langDk, Constants.Security.SuperUserKey);
await LanguageService.CreateAsync(langJp, Constants.Security.SuperUserKey);

IContentType contentType = new ContentTypeBuilder()
.WithAlias("variant")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ private async Task CreateVariantDocument()
.WithCultureInfo("ja-JP")
.Build();

LocalizationService.Save(langDk);
LocalizationService.Save(langJp);
await LanguageService.CreateAsync(langDk, Cms.Core.Constants.Security.SuperUserKey);
await LanguageService.CreateAsync(langJp, Cms.Core.Constants.Security.SuperUserKey);

IContentType contentType = new ContentTypeBuilder()
.WithAlias("variant")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ namespace Umbraco.Test.Search.Examine.Integration.Tests.ContentTests.SearchServi

public class VariantDocumentTests : SearcherTestBase
{

[TestCase(true, "en-US", "Name")]
[TestCase(false, "en-US", "Name")]
[TestCase(true, "da-DK", "Navn")]
Expand Down Expand Up @@ -83,20 +82,34 @@ public async Task CanSearchVariantTextBySegment(bool publish, string culture, st
Assert.That(results.Documents.First().Id, Is.EqualTo(RootKey));
}

[TestCase(true, "da-DK", "Roden")]
[TestCase(true, "ja-JP", "ル-ト")]
public async Task CannotSearchNonExistingNameAfterLanguageDelete(bool publish, string culture, string name)
{
var indexAlias = GetIndexAlias(publish);

await LanguageService.DeleteAsync(culture, Constants.Security.SuperUserKey);

// We can't wait for indexing here, as it's an entire rebuild, not just a single action.
await Task.Delay(4000);

SearchResult results = await Searcher.SearchAsync(indexAlias, name, null, null, null, culture, null, null, 0, 100);
Assert.That(results.Total, Is.EqualTo(0));
}

[SetUp]
public async Task CreateVariantDocument()
{

ILanguage langDk = new LanguageBuilder()
.WithCultureInfo("da-DK")
.WithIsDefault(true)
.Build();
ILanguage langJp = new LanguageBuilder()
.WithCultureInfo("ja-JP")
.Build();

LocalizationService.Save(langDk);
LocalizationService.Save(langJp);
await LanguageService.CreateAsync(langDk, Constants.Security.SuperUserKey);
await LanguageService.CreateAsync(langJp, Constants.Security.SuperUserKey);

IContentType contentType = new ContentTypeBuilder()
.WithAlias("variant")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ public async Task CreateVariantDocument()
.WithCultureInfo("ja-JP")
.Build();

LocalizationService.Save(langDk);
LocalizationService.Save(langJp);
await LanguageService.CreateAsync(langDk, Constants.Security.SuperUserKey);
await LanguageService.CreateAsync(langJp, Constants.Security.SuperUserKey);

IContentType contentType = new ContentTypeBuilder()
.WithAlias("variant")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
using NUnit.Framework;
using Umbraco.Cms.Core.HostedServices;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Search.Core.DependencyInjection;
using Umbraco.Cms.Search.Core.NotificationHandlers;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Test.Search.Examine.Integration.Attributes;
Expand Down Expand Up @@ -37,7 +39,8 @@ public abstract class TestBase : UmbracoIntegrationTest

protected IDataTypeService DataTypeService => GetRequiredService<IDataTypeService>();

protected ILocalizationService LocalizationService => GetRequiredService<ILocalizationService>();
protected ILanguageService LanguageService => GetRequiredService<ILanguageService>();


protected void SaveAndPublish(IContent content)
{
Expand All @@ -55,6 +58,7 @@ protected override void CustomTestSetup(IUmbracoBuilder builder)

builder.Services.AddUnique<IBackgroundTaskQueue, ImmediateBackgroundTaskQueue>();
builder.Services.AddUnique<IServerMessenger, LocalServerMessenger>();
builder.AddNotificationHandler<LanguageDeletedNotification, RebuildIndexesNotificationHandler>();

// the core ConfigureBuilderAttribute won't execute from other assemblies at the moment, so this is a workaround
var testType = Type.GetType(TestContext.CurrentContext.Test.ClassName!);
Expand Down