Skip to content

Commit

Permalink
Show warnings when Azure AI Search is not configured (OrchardCMS#14988)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored and urbanit committed Mar 18, 2024
1 parent 443929d commit 1d1b598
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -82,6 +84,11 @@ public async Task<IActionResult> Index(AzureAIIndexOptions options, PagerParamet
return Forbid();
}

if (!_azureAIOptions.IsConfigurationExists())
{
return NotConfigured();
}

var indexes = (await _indexSettingsService.GetSettingsAsync())
.Select(i => new IndexViewModel { Name = i.IndexName })
.ToList();
Expand All @@ -100,20 +107,19 @@ public async Task<IActionResult> 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 =
Expand All @@ -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<ActionResult> IndexPost(AzureAIIndexOptions options, IEnumerable<string> itemIds)
public async Task<IActionResult> IndexPost(AzureAIIndexOptions options, IEnumerable<string> itemIds)
{
if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes))
{
return Forbid();
}

if (!_azureAIOptions.IsConfigurationExists())
{
return BadRequest();
}

if (itemIds?.Count() > 0)
{
var indexSettings = await _indexSettingsService.GetSettingsAsync();
Expand All @@ -169,13 +180,18 @@ public async Task<ActionResult> IndexPost(AzureAIIndexOptions options, IEnumerab
return RedirectToAction(nameof(Index));
}

public async Task<ActionResult> Create()
public async Task<IActionResult> Create()
{
if (!await _authorizationService.AuthorizeAsync(User, AzureAISearchIndexPermissionHelper.ManageAzureAISearchIndexes))
{
return Forbid();
}

if (!_azureAIOptions.IsConfigurationExists())
{
return NotConfigured();
}

var model = new AzureAISettingsViewModel
{
AnalyzerName = AzureAISearchDefaultOptions.DefaultAnalyzer
Expand All @@ -187,13 +203,18 @@ public async Task<ActionResult> Create()
}

[HttpPost, ActionName(nameof(Create))]
public async Task<ActionResult> CreatePost(AzureAISettingsViewModel model)
public async Task<IActionResult> 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 <em>{0}</em> already exist in Azure AI Search server.", model.IndexName]);
Expand Down Expand Up @@ -244,13 +265,18 @@ public async Task<ActionResult> CreatePost(AzureAISettingsViewModel model)
return View(model);
}

public async Task<ActionResult> Edit(string indexName)
public async Task<IActionResult> 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)
Expand Down Expand Up @@ -283,13 +309,18 @@ public async Task<ActionResult> Edit(string indexName)
}

[HttpPost, ActionName(nameof(Edit))]
public async Task<ActionResult> EditPost(AzureAISettingsViewModel model)
public async Task<IActionResult> 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 <em>{0}</em> doesn't exist in Azure AI Search server.", model.IndexName]);
Expand Down Expand Up @@ -353,13 +384,18 @@ public async Task<ActionResult> EditPost(AzureAISettingsViewModel model)
}

[HttpPost]
public async Task<ActionResult> Delete(string indexName)
public async Task<IActionResult> 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)
Expand All @@ -384,13 +420,18 @@ public async Task<ActionResult> Delete(string indexName)
}

[HttpPost]
public async Task<ActionResult> Rebuild(string indexName)
public async Task<IActionResult> 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)
Expand All @@ -413,13 +454,18 @@ public async Task<ActionResult> Rebuild(string indexName)
}

[HttpPost]
public async Task<ActionResult> Reset(string indexName)
public async Task<IActionResult> 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)
Expand All @@ -441,6 +487,9 @@ public async Task<ActionResult> 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) =>
{
Expand Down
14 changes: 1 addition & 13 deletions src/OrchardCore.Modules/OrchardCore.Search.AzureAI/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -31,23 +30,12 @@ public class Startup(ILogger<Startup> logger, IShellConfiguration shellConfigura

public override void ConfigureServices(IServiceCollection services)
{
if (!services.TryAddAzureAISearchServices(_shellConfiguration, _logger))
{
return;
}

services.TryAddAzureAISearchServices(_shellConfiguration, _logger);
services.AddScoped<INavigationProvider, AdminMenu>();
}

public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
{
var options = serviceProvider.GetRequiredService<IOptions<AzureAISearchDefaultOptions>>().Value;

if (!options.IsConfigurationExists())
{
return;
}

var adminControllerName = typeof(AdminController).ControllerName();

routes.MapAreaControllerRoute(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="alert alert-danger" role="alert">
@T["Azure AI Search has not been configured yet."]
</div>
Original file line number Diff line number Diff line change
@@ -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<AzureAISearchDefaultOptions> AzureAIOptions

@if (!AzureAIOptions.Value.IsConfigurationExists())
{
<div class="alert alert-danger" role="alert">
@T["Azure AI Search has not been configured yet."]
</div>

return;
}

@if (Model.SearchIndexes == null || Model.SearchIndexes?.Count == 0)
{
<div class="alert alert-warning">@T["No indices exist! Please create at least one index to configure Azure AI Search service."]</div>
<div class="alert alert-warning" role="alert">
@T["No indices exist! Please create at least one index to configure Azure AI Search service."]
</div>

return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ public static bool TryAddAzureAISearchServices(this IServiceCollection services,
var section = configuration.GetSection("OrchardCore_AzureAISearch");

var options = section.Get<AzureAISearchDefaultOptions>();

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<AzureAISearchDefaultOptions>(opts =>
Expand All @@ -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 =>
Expand All @@ -58,6 +57,6 @@ public static bool TryAddAzureAISearchServices(this IServiceCollection services,
services.AddRecipeExecutionStep<AzureAISearchIndexResetStep>();
services.AddRecipeExecutionStep<AzureAISearchIndexSettingsStep>();

return true;
return configExists;
}
}

0 comments on commit 1d1b598

Please sign in to comment.