Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show warnings when Azure AI Search is not configured #14988

Merged
merged 1 commit into from
Jan 4, 2024
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
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;
}
}