Fix previous conversion of SearchAll to async ignoring the SortOrder value from SearchableTree (#12595)

* Fix previous conversion of SearchAll to async ignoring the SortOrder value from SearchableTree

* small refactoring

Co-authored-by: Paul Woodland <paul.woodland@pwnewmedia.com>
Co-authored-by: Michael <michael@crossingpaths.be>
This commit is contained in:
Paul Woodland
2022-07-25 11:07:56 +01:00
committed by GitHub
parent b3237c498b
commit f0ba9c469e

View File

@@ -174,100 +174,98 @@ public class EntityController : UmbracoAuthorizedJsonController
return ExamineSearch(query, type, searchFrom, ignoreUserStartNodes);
}
/// <summary>
/// Searches for all content that the user is allowed to see (based on their allowed sections)
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
/// <remarks>
/// Even though a normal entity search will allow any user to search on a entity type that they may not have access to
/// edit, we need
/// to filter these results to the sections they are allowed to edit since this search function is explicitly for the
/// global search
/// so if we showed entities that they weren't allowed to edit they would get errors when clicking on the result.
/// The reason a user is allowed to search individual entity types that they are not allowed to edit is because those
/// search
/// methods might be used in things like pickers in the content editor.
/// </remarks>
[HttpGet]
public async Task<IDictionary<string, TreeSearchResult>> SearchAll(string query)
{
var result = new ConcurrentDictionary<string, TreeSearchResult>();
if (string.IsNullOrEmpty(query))
/// <summary>
/// Searches for all content that the user is allowed to see (based on their allowed sections)
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
/// <remarks>
/// Even though a normal entity search will allow any user to search on a entity type that they may not have access to
/// edit, we need
/// to filter these results to the sections they are allowed to edit since this search function is explicitly for the
/// global search
/// so if we showed entities that they weren't allowed to edit they would get errors when clicking on the result.
/// The reason a user is allowed to search individual entity types that they are not allowed to edit is because those
/// search
/// methods might be used in things like pickers in the content editor.
/// </remarks>
[HttpGet]
public async Task<IDictionary<string, TreeSearchResult>> SearchAll(string query)
{
return result;
}
var culture = ClientCulture();
var allowedSections = _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.AllowedSections.ToArray();
var searchTasks = new List<Task>();
foreach (KeyValuePair<string, SearchableApplicationTree> searchableTree in _searchableTreeCollection
.SearchableApplicationTrees.OrderBy(t => t.Value.SortOrder))
{
if (allowedSections?.Contains(searchableTree.Value.AppAlias) ?? false)
if (string.IsNullOrEmpty(query))
{
Tree? tree = _treeService.GetByAlias(searchableTree.Key);
if (tree == null)
{
continue; //shouldn't occur
}
return new Dictionary<string, TreeSearchResult>();
}
var rootNodeDisplayName = Tree.GetRootNodeDisplayName(tree, _localizedTextService);
if (rootNodeDisplayName is not null)
var culture = ClientCulture();
var allowedSections = _backofficeSecurityAccessor.BackOfficeSecurity?.CurrentUser?.AllowedSections.ToArray();
var searchTasks = new List<Task<KeyValuePair<string, TreeSearchResult>>>();
foreach (KeyValuePair<string, SearchableApplicationTree> searchableTree in _searchableTreeCollection
.SearchableApplicationTrees.OrderBy(t => t.Value.SortOrder))
{
if (allowedSections?.Contains(searchableTree.Value.AppAlias) ?? false)
{
searchTasks.Add(ExecuteSearchAsync(query, culture, searchableTree, rootNodeDisplayName, result));
Tree? tree = _treeService.GetByAlias(searchableTree.Key);
if (tree == null)
{
continue; //shouldn't occur
}
var rootNodeDisplayName = Tree.GetRootNodeDisplayName(tree, _localizedTextService);
if (rootNodeDisplayName is not null)
{
searchTasks.Add(ExecuteSearchAsync(query, culture, searchableTree, rootNodeDisplayName));
}
}
}
var taskResults = await Task.WhenAll(searchTasks);
return new Dictionary<string, TreeSearchResult>(taskResults);
}
await Task.WhenAll(searchTasks);
return result;
}
private static async Task ExecuteSearchAsync(
string query,
string? culture,
KeyValuePair<string, SearchableApplicationTree> searchableTree,
string rootNodeDisplayName,
ConcurrentDictionary<string, TreeSearchResult> result)
{
ISearchableTree searcher = searchableTree.Value.SearchableTree;
const int pageSize = 200;
IEnumerable<SearchResultEntity> results = (
searcher is ISearchableTreeWithCulture searcherWithCulture
? await searcherWithCulture.SearchAsync(query, pageSize, 0, culture: culture)
: await searcher.SearchAsync(query, pageSize, 0))
.WhereNotNull();
var searchResult = new TreeSearchResult
private static async Task<KeyValuePair<string, TreeSearchResult>> ExecuteSearchAsync(
string query,
string? culture,
KeyValuePair<string, SearchableApplicationTree> searchableTree,
string rootNodeDisplayName)
{
Results = results,
TreeAlias = searchableTree.Key,
AppAlias = searchableTree.Value.AppAlias,
JsFormatterService = searchableTree.Value.FormatterService,
JsFormatterMethod = searchableTree.Value.FormatterMethod
};
ISearchableTree searcher = searchableTree.Value.SearchableTree;
const int pageSize = 200;
IEnumerable<SearchResultEntity> results = (
searcher is ISearchableTreeWithCulture searcherWithCulture
? await searcherWithCulture.SearchAsync(query, pageSize, 0, culture: culture)
: await searcher.SearchAsync(query, pageSize, 0))
.WhereNotNull();
result.AddOrUpdate(rootNodeDisplayName, _ => searchResult, (_, _) => searchResult);
}
var searchResult = new TreeSearchResult
{
Results = results,
TreeAlias = searchableTree.Key,
AppAlias = searchableTree.Value.AppAlias,
JsFormatterService = searchableTree.Value.FormatterService,
JsFormatterMethod = searchableTree.Value.FormatterMethod
};
/// <summary>
/// Gets the path for a given node ID
/// </summary>
/// <param name="id"></param>
/// <param name="type"></param>
/// <returns></returns>
public IConvertToActionResult GetPath(int id, UmbracoEntityTypes type)
{
ActionResult<EntityBasic?> foundContentResult = GetResultForId(id, type);
EntityBasic? foundContent = foundContentResult.Value;
if (foundContent is null)
{
return foundContentResult;
return new KeyValuePair<string, TreeSearchResult>(rootNodeDisplayName, searchResult);
}
/// <summary>
/// Gets the path for a given node ID
/// </summary>
/// <param name="id"></param>
/// <param name="type"></param>
/// <returns></returns>
public IConvertToActionResult GetPath(int id, UmbracoEntityTypes type)
{
ActionResult<EntityBasic?> foundContentResult = GetResultForId(id, type);
EntityBasic? foundContent = foundContentResult.Value;
if (foundContent is null)
{
return foundContentResult;
}
return new ActionResult<IEnumerable<int>>(foundContent.Path
.Split(Constants.CharArrays.Comma, StringSplitOptions.RemoveEmptyEntries).Select(
s => int.Parse(s, CultureInfo.InvariantCulture)));