Filter out disallowed content types from the delivery API content index (#14156)

* Filter out disallowed content types from the delivery api content index

* Added .

* Allow children of disallowed content types in the index

---------

Co-authored-by: Elitsa <elm@umbraco.dk>
This commit is contained in:
Kenn Jacobsen
2023-04-27 10:30:30 +02:00
committed by GitHub
parent a0d325cfe0
commit d2a8068ca6
4 changed files with 65 additions and 7 deletions

View File

@@ -70,5 +70,5 @@ public class ApiPublishedContentCache : IApiPublishedContentCache
: null;
private bool IsAllowedContentType(IPublishedContent content)
=> _deliveryApiSettings.DisallowedContentTypeAliases.InvariantContains(content.ContentType.Alias) is false;
=> _deliveryApiSettings.IsAllowedContentType(content);
}

View File

@@ -0,0 +1,19 @@
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
namespace Umbraco.Extensions;
public static class DeliveryApiSettingsExtensions
{
public static bool IsAllowedContentType(this DeliveryApiSettings settings, IPublishedContent content)
=> settings.IsAllowedContentType(content.ContentType.Alias);
public static bool IsDisallowedContentType(this DeliveryApiSettings settings, IPublishedContent content)
=> settings.IsDisallowedContentType(content.ContentType.Alias);
public static bool IsAllowedContentType(this DeliveryApiSettings settings, string contentTypeAlias)
=> settings.IsDisallowedContentType(contentTypeAlias) is false;
public static bool IsDisallowedContentType(this DeliveryApiSettings settings, string contentTypeAlias)
=> settings.DisallowedContentTypeAliases.InvariantContains(contentTypeAlias);
}

View File

@@ -1,9 +1,12 @@
using Examine;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Querying;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Examine;
@@ -12,12 +15,19 @@ public class DeliveryApiContentIndexPopulator : IndexPopulator
private readonly IContentService _contentService;
private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory;
private readonly IDeliveryApiContentIndexValueSetBuilder _deliveryContentIndexValueSetBuilder;
private DeliveryApiSettings _deliveryApiSettings;
public DeliveryApiContentIndexPopulator(IContentService contentService, IDeliveryApiContentIndexValueSetBuilder deliveryContentIndexValueSetBuilder, IUmbracoDatabaseFactory umbracoDatabaseFactory)
public DeliveryApiContentIndexPopulator(
IContentService contentService,
IDeliveryApiContentIndexValueSetBuilder deliveryContentIndexValueSetBuilder,
IUmbracoDatabaseFactory umbracoDatabaseFactory,
IOptionsMonitor<DeliveryApiSettings> deliveryApiSettings)
{
_contentService = contentService;
_deliveryContentIndexValueSetBuilder = deliveryContentIndexValueSetBuilder;
_umbracoDatabaseFactory = umbracoDatabaseFactory;
_deliveryApiSettings = deliveryApiSettings.CurrentValue;
deliveryApiSettings.OnChange(settings => _deliveryApiSettings = settings);
RegisterIndex(Constants.UmbracoIndexes.DeliveryApiContentIndexName);
}
@@ -38,19 +48,31 @@ public class DeliveryApiContentIndexPopulator : IndexPopulator
{
descendants = _contentService.GetPagedDescendants(Constants.System.Root, pageIndex, pageSize, out _, publishedQuery, Ordering.By("Path")).ToArray();
// children of unpublished content can still be published; we need to filter them out, as they're not supposed to go into the index.
// there are a few rules we need to abide to when populating the index:
// - children of unpublished content can still be published; we need to filter them out, as they're not supposed to go into the index.
// - content of disallowed content types are not allowed in the index, but their children are
// as we're querying published content and ordering by path, we can construct a list of "allowed" published content IDs like this.
var allowedDescendants = new List<IContent>();
foreach (IContent content in descendants)
{
if (_deliveryApiSettings.IsDisallowedContentType(content.ContentType.Alias))
{
// the content type is disallowed; make sure we consider all its children as candidates for the index anyway
publishedContentIds.Add(content.Id);
continue;
}
// content at root level is by definition published, because we only fetch published content in the query above.
// content not at root level should be included only if their parents are included (unbroken chain of published content)
if (content.Level == 1 || publishedContentIds.Contains(content.ParentId))
{
publishedContentIds.Add(content.Id);
allowedDescendants.Add(content);
}
}
// now we can utilize the list of "allowed" published content to filter out the ones we don't want in the index.
IContent[] allowedDescendants = descendants.Where(content => publishedContentIds.Contains(content.Id)).ToArray();
ValueSet[] valueSets = _deliveryContentIndexValueSetBuilder.GetValueSets(allowedDescendants).ToArray();
// now build the value sets based on the "allowed" published content only
ValueSet[] valueSets = _deliveryContentIndexValueSetBuilder.GetValueSets(allowedDescendants.ToArray()).ToArray();
foreach (IIndex index in indexes)
{

View File

@@ -1,4 +1,6 @@
using Examine;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
@@ -12,12 +14,19 @@ public class DeliveryApiContentIndexValueSetBuilder : IDeliveryApiContentIndexVa
private readonly ContentIndexHandlerCollection _contentIndexHandlerCollection;
private readonly IScopeProvider _scopeProvider;
private readonly IPublicAccessService _publicAccessService;
private DeliveryApiSettings _deliveryApiSettings;
public DeliveryApiContentIndexValueSetBuilder(ContentIndexHandlerCollection contentIndexHandlerCollection, IScopeProvider scopeProvider, IPublicAccessService publicAccessService)
public DeliveryApiContentIndexValueSetBuilder(
ContentIndexHandlerCollection contentIndexHandlerCollection,
IScopeProvider scopeProvider,
IPublicAccessService publicAccessService,
IOptionsMonitor<DeliveryApiSettings> deliveryApiSettings)
{
_contentIndexHandlerCollection = contentIndexHandlerCollection;
_scopeProvider = scopeProvider;
_publicAccessService = publicAccessService;
_deliveryApiSettings = deliveryApiSettings.CurrentValue;
deliveryApiSettings.OnChange(settings => _deliveryApiSettings = settings);
}
/// <inheritdoc />
@@ -49,11 +58,19 @@ public class DeliveryApiContentIndexValueSetBuilder : IDeliveryApiContentIndexVa
private bool CanIndex(IContent content)
{
// is the content in a state that is allowed in the index?
if (content.Published is false || content.Trashed)
{
return false;
}
// is the content type allowed in the index?
if (_deliveryApiSettings.IsDisallowedContentType(content.ContentType.Alias))
{
return false;
}
// is the content protected?
using (_scopeProvider.CreateScope(autoComplete: true))
{
if (_publicAccessService.IsProtected(content.Path).Success)