From bdad29fce2ba2f3020387cac2cf9c5869861a163 Mon Sep 17 00:00:00 2001 From: Mike Alhayek Date: Thu, 4 Jan 2024 08:28:36 -0800 Subject: [PATCH] Show warnings when Azure AI Search is not configured --- .../Controllers/AdminController.cs | 81 +++++++++++++++---- .../OrchardCore.Search.AzureAI/Startup.cs | 14 +--- .../Views/Admin/NotConfigured.cshtml | 3 + .../Views/AzureAISearchSettings.Edit.cshtml | 15 +++- .../Extensions/ServiceCollectionExtensions.cs | 11 ++- 5 files changed, 88 insertions(+), 36 deletions(-) create mode 100644 src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/Admin/NotConfigured.cshtml diff --git a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Controllers/AdminController.cs b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Controllers/AdminController.cs index 996e53b7e65..7c4e14ea9e4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Controllers/AdminController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Controllers/AdminController.cs @@ -29,6 +29,8 @@ namespace OrchardCore.Search.AzureAI.Controllers; public class AdminController : Controller { + private const string _optionsSearch = "Options.Search"; + private readonly ISiteService _siteService; private readonly IAuthorizationService _authorizationService; private readonly AzureAISearchIndexManager _indexManager; @@ -82,6 +84,11 @@ public async Task Index(AzureAIIndexOptions options, PagerParamet return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return NotConfigured(); + } + var indexes = (await _indexSettingsService.GetSettingsAsync()) .Select(i => new IndexViewModel { Name = i.IndexName }) .ToList(); @@ -100,20 +107,19 @@ public async Task Index(AzureAIIndexOptions options, PagerParamet .Skip(pager.GetStartIndex()) .Take(pager.PageSize).ToList(); - // Maintain previous route data when generating page links.S - RouteValueDictionary routeValues = null; + // Maintain previous route data when generating page links. + var routeData = new RouteData(); - if (!string.IsNullOrWhiteSpace(options.Search)) + if (!string.IsNullOrEmpty(options.Search)) { - routeValues = []; - routeValues.TryAdd("Options.Search", options.Search); + routeData.Values.TryAdd(_optionsSearch, options.Search); } var model = new AdminIndexViewModel { Indexes = indexes, Options = options, - Pager = await _shapeFactory.PagerAsync(pager, totalIndexes, routeValues) + Pager = await _shapeFactory.PagerAsync(pager, totalIndexes, routeData) }; model.Options.ContentsBulkAction = @@ -130,19 +136,24 @@ public ActionResult IndexFilterPOST(AdminIndexViewModel model) => RedirectToAction(nameof(Index), new RouteValueDictionary { - { "Options.Search", model.Options.Search } + { _optionsSearch, model.Options.Search } }); - + [HttpPost, ActionName(nameof(Index))] [FormValueRequired("submit.BulkAction")] - public async Task IndexPost(AzureAIIndexOptions options, IEnumerable itemIds) + public async Task IndexPost(AzureAIIndexOptions options, IEnumerable itemIds) { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return BadRequest(); + } + if (itemIds?.Count() > 0) { var indexSettings = await _indexSettingsService.GetSettingsAsync(); @@ -169,13 +180,18 @@ public async Task IndexPost(AzureAIIndexOptions options, IEnumerab return RedirectToAction(nameof(Index)); } - public async Task Create() + public async Task Create() { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return NotConfigured(); + } + var model = new AzureAISettingsViewModel { AnalyzerName = AzureAISearchDefaultOptions.DefaultAnalyzer @@ -187,13 +203,18 @@ public async Task Create() } [HttpPost, ActionName(nameof(Create))] - public async Task CreatePost(AzureAISettingsViewModel model) + public async Task CreatePost(AzureAISettingsViewModel model) { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return BadRequest(); + } + if (ModelState.IsValid && await _indexManager.ExistsAsync(model.IndexName)) { ModelState.AddModelError(nameof(AzureAISettingsViewModel.IndexName), S["An index named {0} already exist in Azure AI Search server.", model.IndexName]); @@ -244,13 +265,18 @@ public async Task CreatePost(AzureAISettingsViewModel model) return View(model); } - public async Task Edit(string indexName) + public async Task Edit(string indexName) { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return NotConfigured(); + } + var settings = await _indexSettingsService.GetAsync(indexName); if (settings == null) @@ -283,13 +309,18 @@ public async Task Edit(string indexName) } [HttpPost, ActionName(nameof(Edit))] - public async Task EditPost(AzureAISettingsViewModel model) + public async Task EditPost(AzureAISettingsViewModel model) { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return BadRequest(); + } + if (ModelState.IsValid && !await _indexManager.ExistsAsync(model.IndexName)) { ModelState.AddModelError(nameof(AzureAISettingsViewModel.IndexName), S["The index named {0} doesn't exist in Azure AI Search server.", model.IndexName]); @@ -353,13 +384,18 @@ public async Task EditPost(AzureAISettingsViewModel model) } [HttpPost] - public async Task Delete(string indexName) + public async Task Delete(string indexName) { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return BadRequest(); + } + var exists = await _indexManager.ExistsAsync(indexName); if (!exists) @@ -384,13 +420,18 @@ public async Task Delete(string indexName) } [HttpPost] - public async Task Rebuild(string indexName) + public async Task Rebuild(string indexName) { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return BadRequest(); + } + var settings = await _indexSettingsService.GetAsync(indexName); if (settings == null) @@ -413,13 +454,18 @@ public async Task Rebuild(string indexName) } [HttpPost] - public async Task Reset(string indexName) + public async Task Reset(string indexName) { if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes)) { return Forbid(); } + if (!_azureAIOptions.IsConfigurationExists()) + { + return BadRequest(); + } + var settings = await _indexSettingsService.GetAsync(indexName); if (settings == null) @@ -441,6 +487,9 @@ public async Task Reset(string indexName) return RedirectToAction(nameof(Index)); } + private IActionResult NotConfigured() + => View("NotConfigured"); + private static Task AsyncContentItemsAsync(string indexName) => HttpBackgroundJob.ExecuteAfterEndOfRequestAsync("sync-content-items-azure-ai-" + indexName, async (scope) => { diff --git a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Startup.cs index b48bcb8e198..fba9cdb30cc 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Startup.cs @@ -16,7 +16,6 @@ using OrchardCore.Search.AzureAI.Controllers; using OrchardCore.Search.AzureAI.Deployment; using OrchardCore.Search.AzureAI.Drivers; -using OrchardCore.Search.AzureAI.Models; using OrchardCore.Search.AzureAI.Services; using OrchardCore.Settings; @@ -31,23 +30,12 @@ public class Startup(ILogger logger, IShellConfiguration shellConfigura public override void ConfigureServices(IServiceCollection services) { - if (!services.TryAddAzureAISearchServices(_shellConfiguration, _logger)) - { - return; - } - + services.TryAddAzureAISearchServices(_shellConfiguration, _logger); services.AddScoped(); } public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) { - var options = serviceProvider.GetRequiredService>().Value; - - if (!options.IsConfigurationExists()) - { - return; - } - var adminControllerName = typeof(AdminController).ControllerName(); routes.MapAreaControllerRoute( diff --git a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/Admin/NotConfigured.cshtml b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/Admin/NotConfigured.cshtml new file mode 100644 index 00000000000..5937c0c408f --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/Admin/NotConfigured.cshtml @@ -0,0 +1,3 @@ + diff --git a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/AzureAISearchSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/AzureAISearchSettings.Edit.cshtml index 864e433973e..c46e0e52f45 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/AzureAISearchSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Views/AzureAISearchSettings.Edit.cshtml @@ -1,12 +1,25 @@ +@using Microsoft.Extensions.Options @using OrchardCore.Search.AzureAI @using OrchardCore.Search.AzureAI.Models @using OrchardCore.Search.AzureAI.ViewModels @model AzureAISearchSettingsViewModel +@inject IOptions AzureAIOptions + +@if (!AzureAIOptions.Value.IsConfigurationExists()) +{ + + + return; +} @if (Model.SearchIndexes == null || Model.SearchIndexes?.Count == 0) { -
@T["No indices exist! Please create at least one index to configure Azure AI Search service."]
+ return; } diff --git a/src/OrchardCore/OrchardCore.Search.AzureAI.Core/Extensions/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Search.AzureAI.Core/Extensions/ServiceCollectionExtensions.cs index 00dde35c723..4c062693615 100644 --- a/src/OrchardCore/OrchardCore.Search.AzureAI.Core/Extensions/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Search.AzureAI.Core/Extensions/ServiceCollectionExtensions.cs @@ -21,12 +21,11 @@ public static bool TryAddAzureAISearchServices(this IServiceCollection services, var section = configuration.GetSection("OrchardCore_AzureAISearch"); var options = section.Get(); - + var configExists = true; if (string.IsNullOrWhiteSpace(options?.Endpoint) || string.IsNullOrWhiteSpace(options?.Credential?.Key)) { - logger.LogError("Azure AI Search module is enabled. However, the connection settings are not provided in configuration file.."); - - return false; + configExists = false; + logger.LogError("Azure AI Search module is enabled. However, the connection settings are not provided in configuration file."); } services.Configure(opts => @@ -37,7 +36,7 @@ public static bool TryAddAzureAISearchServices(this IServiceCollection services, opts.Analyzers = options.Analyzers == null || options.Analyzers.Length == 0 ? AzureAISearchDefaultOptions.DefaultAnalyzers : options.Analyzers; - opts.SetConfigurationExists(true); + opts.SetConfigurationExists(configExists); }); services.AddAzureClients(builder => @@ -58,6 +57,6 @@ public static bool TryAddAzureAISearchServices(this IServiceCollection services, services.AddRecipeExecutionStep(); services.AddRecipeExecutionStep(); - return true; + return configExists; } }