Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into ma/dispose-async
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek committed Dec 8, 2023
2 parents 9ee8f95 + ea83196 commit 2d19a56
Show file tree
Hide file tree
Showing 17 changed files with 320 additions and 124 deletions.
12 changes: 4 additions & 8 deletions .github/workflows/preview_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,13 @@ jobs:
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Deploy preview docker image for linux and windows
shell: pwsh
- name: Deploy preview docker images
if: matrix.os == 'ubuntu-latest'
shell: pwsh
run: |
Get-ChildItem ./src/OrchardCore.Cms.Web/App_Data -Recurse | Remove-Item -Recurse -Confirm:$false
Get-ChildItem ./src/OrchardCore.Cms.Web/App_Data_Tests -Recurse | Remove-Item -Recurse -Confirm:$false
$output = [System.IO.Path]::GetFullPath("./.build/release")
dotnet publish -c Release --property:PublishDir=$output --no-build --framework net8.0
docker buildx build -f Dockerfile-CI --platform=linux/amd64 .
docker buildx build -f Dockerfile-CI --load --platform=linux/amd64 -t orchardproject/orchardcore-cms-linux:dev .
docker push orchardproject/orchardcore-cms-linux:dev
docker buildx build -f Dockerfile-CI --platform=windows/amd64 .
docker buildx build -f Dockerfile-CI --load --platform=windows/amd64 -t orchardproject/orchardcore-cms-windows:dev .
docker push orchardproject/orchardcore-cms-windows:dev
docker buildx build -f Dockerfile-CI --platform=linux/amd64 -t orchardproject/orchardcore-cms-linux:dev --push .
docker buildx build -f Dockerfile-CI --platform=windows/amd64 -t orchardproject/orchardcore-cms-windows:dev --push .
14 changes: 4 additions & 10 deletions .github/workflows/release_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,13 @@ jobs:
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Deploy release docker image for linux and windows
shell: pwsh
- name: Deploy release docker images
if: matrix.os == 'ubuntu-latest'
shell: pwsh
run: |
Get-ChildItem ./src/OrchardCore.Cms.Web/App_Data -Recurse | Remove-Item -Recurse -Confirm:$false
Get-ChildItem ./src/OrchardCore.Cms.Web/App_Data_Tests -Recurse | Remove-Item -Recurse -Confirm:$false
$output = [System.IO.Path]::GetFullPath("./.build/release")
dotnet publish -c Release --property:PublishDir=$output --no-build --framework net8.0
docker buildx build -f Dockerfile-CI --platform=linux/amd64 .
docker buildx build -f Dockerfile-CI --load --platform=linux/amd64 -t orchardproject/orchardcore-cms-linux:latest -t orchardproject/orchardcore-cms-linux:${{ steps.get_version.outputs.VERSION }} .
docker push orchardproject/orchardcore-cms-linux:latest
docker push "orchardproject/orchardcore-cms-linux:${{ steps.get_version.outputs.VERSION }}"
docker buildx build -f Dockerfile-CI --platform=windows/amd64 .
docker buildx build -f Dockerfile-CI --load --platform=windows/amd64 -t orchardproject/orchardcore-cms-windows:latest -t orchardproject/orchardcore-cms-windows:${{ steps.get_version.outputs.VERSION }} .
docker push orchardproject/orchardcore-cms-windows:latest
docker push "orchardproject/orchardcore-cms-windows:${{ steps.get_version.outputs.VERSION }}"
docker buildx build -f Dockerfile-CI --platform=linux/amd64 -t orchardproject/orchardcore-cms-linux:latest -t orchardproject/orchardcore-cms-linux:${{ steps.get_version.outputs.VERSION }} --push .
docker buildx build -f Dockerfile-CI --platform=windows/amd64 -t orchardproject/orchardcore-cms-windows:latest -t orchardproject/orchardcore-cms-windows:${{ steps.get_version.outputs.VERSION }} --push .
Original file line number Diff line number Diff line change
@@ -1,75 +1,119 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Localization;
using Nest;
using OrchardCore.DisplayManagement.Entities;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Mvc.ModelBinding;
using OrchardCore.Search.Elasticsearch.Core.Models;
using OrchardCore.Search.Elasticsearch.Core.Services;
using OrchardCore.Search.Elasticsearch.ViewModels;
using OrchardCore.Settings;

namespace OrchardCore.Search.Elasticsearch.Drivers
namespace OrchardCore.Search.Elasticsearch.Drivers;

public class ElasticSettingsDisplayDriver : SectionDisplayDriver<ISite, ElasticSettings>
{
public class ElasticSettingsDisplayDriver : SectionDisplayDriver<ISite, ElasticSettings>
public const string GroupId = "elasticsearch";

private static readonly char[] _separator = [',', ' '];
private static readonly JsonSerializerOptions _jsonSerializerOptions = new()
{
WriteIndented = true,
};
private readonly ElasticIndexSettingsService _elasticIndexSettingsService;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IAuthorizationService _authorizationService;
private readonly IElasticClient _elasticClient;
protected readonly IStringLocalizer S;

public ElasticSettingsDisplayDriver(
ElasticIndexSettingsService elasticIndexSettingsService,
IHttpContextAccessor httpContextAccessor,
IAuthorizationService authorizationService,
IElasticClient elasticClient,
IStringLocalizer<ElasticSettingsDisplayDriver> stringLocalizer
)
{
public const string GroupId = "elasticsearch";
private readonly ElasticIndexSettingsService _elasticIndexSettingsService;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IAuthorizationService _authorizationService;
_elasticIndexSettingsService = elasticIndexSettingsService;
_httpContextAccessor = httpContextAccessor;
_authorizationService = authorizationService;
_elasticClient = elasticClient;
S = stringLocalizer;
}

public ElasticSettingsDisplayDriver(
ElasticIndexSettingsService elasticIndexSettingsService,
IHttpContextAccessor httpContextAccessor,
IAuthorizationService authorizationService
)
public override IDisplayResult Edit(ElasticSettings settings)
=> Initialize<ElasticSettingsViewModel>("ElasticSettings_Edit", async model =>
{
_elasticIndexSettingsService = elasticIndexSettingsService;
_httpContextAccessor = httpContextAccessor;
_authorizationService = authorizationService;
model.SearchIndex = settings.SearchIndex;
model.SearchFields = string.Join(", ", settings.DefaultSearchFields ?? []);
model.SearchIndexes = (await _elasticIndexSettingsService.GetSettingsAsync()).Select(x => x.IndexName);
model.DefaultQuery = settings.DefaultQuery;
model.SearchType = settings.GetSearchType();
model.SearchTypes = [
new(S["Multi-Match Query (Default)"], string.Empty),
new(S["Query String Query"], ElasticSettings.QueryStringSearchType),
new(S["Custom Query"], ElasticSettings.CustomSearchType),
];
}).Location("Content:2")
.RenderWhen(() => _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, Permissions.ManageElasticIndexes))
.OnGroup(GroupId);

public override async Task<IDisplayResult> UpdateAsync(ElasticSettings section, BuildEditorContext context)
{
if (!string.Equals(GroupId, context.GroupId, StringComparison.OrdinalIgnoreCase))
{
return null;
}

public override async Task<IDisplayResult> EditAsync(ElasticSettings settings, BuildEditorContext context)
if (!await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, Permissions.ManageElasticIndexes))
{
var user = _httpContextAccessor.HttpContext?.User;
return null;
}

if (!await _authorizationService.AuthorizeAsync(user, Permissions.ManageElasticIndexes))
{
return null;
}
var model = new ElasticSettingsViewModel();

return Initialize<ElasticSettingsViewModel>("ElasticSettings_Edit", async model =>
{
model.SearchIndex = settings.SearchIndex;
model.SearchFields = string.Join(", ", settings.DefaultSearchFields ?? Array.Empty<string>());
model.SearchIndexes = (await _elasticIndexSettingsService.GetSettingsAsync()).Select(x => x.IndexName);
model.AllowElasticQueryStringQueryInSearch = settings.AllowElasticQueryStringQueryInSearch;
}).Location("Content:2").OnGroup(GroupId);
}
await context.Updater.TryUpdateModelAsync(model, Prefix);

public override async Task<IDisplayResult> UpdateAsync(ElasticSettings section, BuildEditorContext context)
{
var user = _httpContextAccessor.HttpContext?.User;
section.DefaultQuery = null;
section.SearchIndex = model.SearchIndex;
section.DefaultSearchFields = model.SearchFields?.Split(_separator, StringSplitOptions.RemoveEmptyEntries);
section.SearchType = model.SearchType ?? string.Empty;

if (!await _authorizationService.AuthorizeAsync(user, Permissions.ManageElasticIndexes))
if (model.SearchType == ElasticSettings.CustomSearchType)
{
if (string.IsNullOrWhiteSpace(model.DefaultQuery))
{
return null;
context.Updater.ModelState.AddModelError(Prefix, nameof(model.DefaultQuery), S["Please provide the default query."]);
}

if (context.GroupId.Equals(GroupId, StringComparison.OrdinalIgnoreCase))
else if (!JsonHelpers.TryParse(model.DefaultQuery, out var document))
{
var model = new ElasticSettingsViewModel();
context.Updater.ModelState.AddModelError(Prefix, nameof(model.DefaultQuery), S["The provided query is not formatted correctly."]);
}
else
{
section.DefaultQuery = JsonSerializer.Serialize(document, _jsonSerializerOptions);

await context.Updater.TryUpdateModelAsync(model, Prefix);
try
{
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(model.DefaultQuery));

section.SearchIndex = model.SearchIndex;
section.DefaultSearchFields = model.SearchFields?.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
section.AllowElasticQueryStringQueryInSearch = model.AllowElasticQueryStringQueryInSearch;
var searchRequest = await _elasticClient.RequestResponseSerializer.DeserializeAsync<SearchRequest>(stream);
}
catch
{
context.Updater.ModelState.AddModelError(Prefix, nameof(model.DefaultQuery), S["Invalid query provided."]);
}
}

return await EditAsync(section, context);
}

return await EditAsync(section, context);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Fluid.Values;
using Microsoft.Extensions.Logging;
using Nest;
using OrchardCore.Entities;
using OrchardCore.Liquid;
using OrchardCore.Search.Abstractions;
using OrchardCore.Search.Elasticsearch.Core.Models;
using OrchardCore.Search.Elasticsearch.Core.Services;
Expand All @@ -16,20 +21,29 @@ public class ElasticsearchService : ISearchService
private readonly ElasticIndexManager _elasticIndexManager;
private readonly ElasticIndexSettingsService _elasticIndexSettingsService;
private readonly IElasticSearchQueryService _elasticsearchQueryService;
private readonly IElasticClient _elasticClient;
private readonly JavaScriptEncoder _javaScriptEncoder;
private readonly ILiquidTemplateManager _liquidTemplateManager;
private readonly ILogger _logger;

public ElasticsearchService(
ISiteService siteService,
ElasticIndexManager elasticIndexManager,
ElasticIndexSettingsService elasticIndexSettingsService,
IElasticSearchQueryService elasticsearchQueryService,
IElasticClient elasticClient,
JavaScriptEncoder javaScriptEncoder,
ILiquidTemplateManager liquidTemplateManager,
ILogger<ElasticsearchService> logger
)
{
_siteService = siteService;
_elasticIndexManager = elasticIndexManager;
_elasticIndexSettingsService = elasticIndexSettingsService;
_elasticsearchQueryService = elasticsearchQueryService;
_elasticClient = elasticClient;
_javaScriptEncoder = javaScriptEncoder;
_liquidTemplateManager = liquidTemplateManager;
_logger = logger;
}

Expand Down Expand Up @@ -63,27 +77,44 @@ public async Task<SearchResult> SearchAsync(string indexName, string term, int s

try
{
var searchType = searchSettings.GetSearchType();
QueryContainer query = null;

if (searchSettings.AllowElasticQueryStringQueryInSearch)
if (searchType == ElasticSettings.CustomSearchType && !string.IsNullOrWhiteSpace(searchSettings.DefaultQuery))
{
query = new QueryStringQuery
var tokenizedContent = await _liquidTemplateManager.RenderStringAsync(searchSettings.DefaultQuery, _javaScriptEncoder,
new Dictionary<string, FluidValue>()
{
["term"] = new StringValue(term)
});

try
{
Fields = searchSettings.DefaultSearchFields,
Analyzer = await _elasticIndexSettingsService.GetQueryAnalyzerAsync(index),
Query = term
};
using var stream = new MemoryStream(Encoding.UTF8.GetBytes(tokenizedContent));

var searchRequest = await _elasticClient.RequestResponseSerializer.DeserializeAsync<SearchRequest>(stream);

query = searchRequest.Query;
}
catch { }
}
else
else if (searchType == ElasticSettings.QueryStringSearchType)
{
query = new MultiMatchQuery
query = new QueryStringQuery
{
Fields = searchSettings.DefaultSearchFields,
Analyzer = await _elasticIndexSettingsService.GetQueryAnalyzerAsync(index),
Query = term
};
}

query ??= new MultiMatchQuery
{
Fields = searchSettings.DefaultSearchFields,
Analyzer = await _elasticIndexSettingsService.GetQueryAnalyzerAsync(index),
Query = term
};

result.ContentItemIds = await _elasticsearchQueryService.ExecuteQueryAsync(index, query, null, start, pageSize);
result.Success = true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace OrchardCore.Search.Elasticsearch.ViewModels
{
public class ElasticSettingsViewModel
{
public string Analyzer { get; set; }

public string SearchIndex { get; set; }

public IEnumerable<string> SearchIndexes { get; set; }

public string SearchFields { get; set; }
public bool AllowElasticQueryStringQueryInSearch { get; set; }

public string DefaultQuery { get; set; }

public string SearchType { get; set; }

[BindNever]
public IEnumerable<SelectListItem> SearchTypes { get; set; }
}
}
Loading

0 comments on commit 2d19a56

Please sign in to comment.