Files
Umbraco-CMS/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Published/NestedContentTests.cs

285 lines
12 KiB
C#
Raw Normal View History

// Copyright (c) Umbraco.
// See LICENSE for more details.
2017-09-26 14:57:50 +02:00
using System.Collections.Generic;
using System.Linq;
2020-09-28 08:26:21 +02:00
using Microsoft.Extensions.Logging;
2020-09-18 14:37:19 +02:00
using Microsoft.Extensions.Logging.Abstractions;
2017-09-26 14:57:50 +02:00
using Moq;
using NUnit.Framework;
Content Delivery API (#14051) * Add the core parts of the headless PoC * Add Content API project (WIP - loads of TODOs and dupes that need to be fixed!) * Rename the content API project and namespaces * Fixed bad merge * Rename everything "Headless" to "ContentApi" or "Api" * Refactor Content + Media: Key => Id, Name not nullable * Make Content API property return value types independent of datatype configuration * Clean up refactorings * First stab at an expansion strategy using content picker as example implementation * Use named JSON options for content API serialization * Proper inclusion and registration of the content API * Introduce API media builder * Make MNTP return API content/media depending on configuration (instead of links) and support output expansion * Content API: Get by controllers (#13740) * Adding ContentApiControllerBase * Adding get by id and url controllers * Change route of get all test controller * Rename to ContentApiController * Refactoring * Removing test controller * Content API: Add start-node header value to deal with url collisions (#13746) * Use start-node header value to deal with url collisions * Cleanup * Rename "url" param to "path" * Adding a start node service to get the start-node header value * Trim '/' from both beginning and end * Content API: Support Accept-Language header (#13831) * Move the content API JSON type resolver to an appropriate namespace * Add localization based on Accept-Language header * Content API: Output expansion (#13848) * Implement request based output expansion strategy + expansion output cache at property level * Slighty leaner implementation for default output expansion strategy * Clarify the code a bit * Fix bad merge * Encapsulate content API dependencies in the DI * Support multi-site and multi-culture routing + a little rename/refactor (#13882) * Support multi-site and multi-culture routing + a little rename/refactor * Make the by route controller handle root nodes * Rename Url to Path in API content output * Add a few comments for magic route creation * Rename services from "Default" to "Noop" * Ensure that Umbraco can boot without adding "AddContentApi()" to ConfigureServices * Moved incorrectly placed media builder * Fix API routes (#13915) * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Include umbraco properties (width, height, ...) in the Media Properties collection (#14023) * Move umbraco properties (width, height, ...) to the Properties collection of the API Media model * Don't output the umbracoFile property of media items * Add content type deny list (#14025) * Create a deny list of content types and utilize it for output generation * Add unit tests * Dedicated property cache level for Content API (#14027) * Support redirect tracking (#14033) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add cultures and their routes to the API output (#14038) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add culture routes to root output (for HREFLANG support) * Rename redirect service method to better match its purpose * Review changes * Delivery API: Query controller (#14041) * Initial commit * Custom ContentAPIFieldDefinitionCollection * Make index IUmbracoContentIndex * Add querying for children by parent id (key) * Add missing interface * Adding querying endpoint * Test code * Compose unpublishedValueSet, so that you get the correct data in the ContentAPI index * Renaming * Fix ancestorKeys index values * Adding IApiQueryExtensionService to be able to query the ContentAPI index in a generic way * Fix IApiQueryService and clean up QueryContentApiController using it * Support querying for path * Fix content API indexing * Fix default sorting * Implement concrete QueryOption implementations * Introduce new ExecuteQuery that uses the Core OptionHandlers * Implement ExecuteQuery * Change ExecuteQuery signature and implementation * Implement demo sorting and fetching * Add query option handlers and collection builder for them * Cleanup * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Test commit * Refactored interfaces for the query handlers and for the selectors (that will handle the value of the fetch query option) * Implemented a base class for the query options * Refactored the names of the selectors and made use of the base class * Refactored the ApiQueryService * Refactored the QueryContentApiController.cs * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Fixing merge gone wrong * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Make fetching work with the new setup * Moving files to dedicated folders * Removing ? for array * Rename selector query method * Implement FilterHandler and some filters * Implement SortHandler and sort some sorts * Refactoring * Adding more fields to index due to querying * Appending filtering and sorting queries * Implementing a new ISelectorHandler without Examine types * Re-implementing the collection to have a dedicated one for the selectors * Implementing a new IFilterHandler without Examine types & refactoring the filters implementing it * Adding a new collection dedicated to filters * Renaming the old collection * Implementing a new ISortHandler without Examine types & refactoring the sorts implementing it * Adding a new collection for the sorts & adding all collections to UmbracoBuilder.Collections * Refactoring the service to use the new collections and types * Refactoring the fields in ContentApiFieldDefinitionCollection * Remove nullability in Handlers * Don't return null for selector * Add TODO for having the filters support negation * Changing the SortType to FieldType with our custom types on the SortOption * Fix AncestorsSelector * Fix ApiQueryService * Documentation * Fix Swagger docs * Refactor the QueryContentApiController * Adding handling for the IApiContentResponse in the JsonTypeResolver * Refactor the service to use a safe fallback value in Examine queries * Adding Noop for the IApiQueryService * Cleanup * Remove comment * Fix name field for indexing * Don't inherit QueryOptionBase in filters * Fix casing for API index constant + swap FIXME with TODO * Add TODO for handling missing fetch with start-item header * Rename query handler parameters to not leak source (i.e. query string) --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa <> Co-authored-by: Zeegaan <nge@umbraco.dk> * Delivery API: Adding pagination to query endpoint (#14083) * Adding pagination to query endpoint * Optimize the paging using Examine directly * Fix comment * Remove skip/take code duplication --------- Co-authored-by: kjac <kja@umbraco.dk> * Add missing CompatibilitySuppressions.xml * Make Delivery API packable * Make Api.Common packable * Renamed extension method and namespace so it is discoverable * Untangle ApiVersion configuration into api.common, so delivery api do not require the management api to boot. * configure options in management api * RTE output as JSON for Content API (#14067) * Conditionally serve RTE output as JSON instead of HTML * Fixed merge * Rename to Delivery API (#14119) * Rename ContentApi to DeliveryApi * Rename delivery API index implementation * Update comments from "Content API" to "Delivery API" * Rename project from Content to Delivery * Add dedicated controller base for content delivery API * Rename delivery API content index to include "content" specifically * Fix compat suppressions --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-04-19 11:21:31 +02:00
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.Models.DeliveryApi;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Core.PublishedCache.Internal;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Serialization;
using Umbraco.Extensions;
2017-09-26 14:57:50 +02:00
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Published;
[TestFixture]
public class NestedContentTests
2017-09-26 14:57:50 +02:00
{
private (IPublishedContentType, IPublishedContentType) CreateContentTypes()
2017-09-26 14:57:50 +02:00
{
var logger = Mock.Of<ILogger<ProfilingLogger>>();
var loggerFactory = NullLoggerFactory.Instance;
var profiler = Mock.Of<IProfiler>();
var proflog = new ProfilingLogger(logger, profiler);
var localizationService = Mock.Of<ILocalizationService>();
2017-09-26 14:57:50 +02:00
PropertyEditorCollection editors = null;
var editor = new NestedContentPropertyEditor(
Mock.Of<IDataValueEditorFactory>(),
Content Delivery API (#14051) * Add the core parts of the headless PoC * Add Content API project (WIP - loads of TODOs and dupes that need to be fixed!) * Rename the content API project and namespaces * Fixed bad merge * Rename everything "Headless" to "ContentApi" or "Api" * Refactor Content + Media: Key => Id, Name not nullable * Make Content API property return value types independent of datatype configuration * Clean up refactorings * First stab at an expansion strategy using content picker as example implementation * Use named JSON options for content API serialization * Proper inclusion and registration of the content API * Introduce API media builder * Make MNTP return API content/media depending on configuration (instead of links) and support output expansion * Content API: Get by controllers (#13740) * Adding ContentApiControllerBase * Adding get by id and url controllers * Change route of get all test controller * Rename to ContentApiController * Refactoring * Removing test controller * Content API: Add start-node header value to deal with url collisions (#13746) * Use start-node header value to deal with url collisions * Cleanup * Rename "url" param to "path" * Adding a start node service to get the start-node header value * Trim '/' from both beginning and end * Content API: Support Accept-Language header (#13831) * Move the content API JSON type resolver to an appropriate namespace * Add localization based on Accept-Language header * Content API: Output expansion (#13848) * Implement request based output expansion strategy + expansion output cache at property level * Slighty leaner implementation for default output expansion strategy * Clarify the code a bit * Fix bad merge * Encapsulate content API dependencies in the DI * Support multi-site and multi-culture routing + a little rename/refactor (#13882) * Support multi-site and multi-culture routing + a little rename/refactor * Make the by route controller handle root nodes * Rename Url to Path in API content output * Add a few comments for magic route creation * Rename services from "Default" to "Noop" * Ensure that Umbraco can boot without adding "AddContentApi()" to ConfigureServices * Moved incorrectly placed media builder * Fix API routes (#13915) * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Include umbraco properties (width, height, ...) in the Media Properties collection (#14023) * Move umbraco properties (width, height, ...) to the Properties collection of the API Media model * Don't output the umbracoFile property of media items * Add content type deny list (#14025) * Create a deny list of content types and utilize it for output generation * Add unit tests * Dedicated property cache level for Content API (#14027) * Support redirect tracking (#14033) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add cultures and their routes to the API output (#14038) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add culture routes to root output (for HREFLANG support) * Rename redirect service method to better match its purpose * Review changes * Delivery API: Query controller (#14041) * Initial commit * Custom ContentAPIFieldDefinitionCollection * Make index IUmbracoContentIndex * Add querying for children by parent id (key) * Add missing interface * Adding querying endpoint * Test code * Compose unpublishedValueSet, so that you get the correct data in the ContentAPI index * Renaming * Fix ancestorKeys index values * Adding IApiQueryExtensionService to be able to query the ContentAPI index in a generic way * Fix IApiQueryService and clean up QueryContentApiController using it * Support querying for path * Fix content API indexing * Fix default sorting * Implement concrete QueryOption implementations * Introduce new ExecuteQuery that uses the Core OptionHandlers * Implement ExecuteQuery * Change ExecuteQuery signature and implementation * Implement demo sorting and fetching * Add query option handlers and collection builder for them * Cleanup * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Test commit * Refactored interfaces for the query handlers and for the selectors (that will handle the value of the fetch query option) * Implemented a base class for the query options * Refactored the names of the selectors and made use of the base class * Refactored the ApiQueryService * Refactored the QueryContentApiController.cs * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Fixing merge gone wrong * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Make fetching work with the new setup * Moving files to dedicated folders * Removing ? for array * Rename selector query method * Implement FilterHandler and some filters * Implement SortHandler and sort some sorts * Refactoring * Adding more fields to index due to querying * Appending filtering and sorting queries * Implementing a new ISelectorHandler without Examine types * Re-implementing the collection to have a dedicated one for the selectors * Implementing a new IFilterHandler without Examine types & refactoring the filters implementing it * Adding a new collection dedicated to filters * Renaming the old collection * Implementing a new ISortHandler without Examine types & refactoring the sorts implementing it * Adding a new collection for the sorts & adding all collections to UmbracoBuilder.Collections * Refactoring the service to use the new collections and types * Refactoring the fields in ContentApiFieldDefinitionCollection * Remove nullability in Handlers * Don't return null for selector * Add TODO for having the filters support negation * Changing the SortType to FieldType with our custom types on the SortOption * Fix AncestorsSelector * Fix ApiQueryService * Documentation * Fix Swagger docs * Refactor the QueryContentApiController * Adding handling for the IApiContentResponse in the JsonTypeResolver * Refactor the service to use a safe fallback value in Examine queries * Adding Noop for the IApiQueryService * Cleanup * Remove comment * Fix name field for indexing * Don't inherit QueryOptionBase in filters * Fix casing for API index constant + swap FIXME with TODO * Add TODO for handling missing fetch with start-item header * Rename query handler parameters to not leak source (i.e. query string) --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa <> Co-authored-by: Zeegaan <nge@umbraco.dk> * Delivery API: Adding pagination to query endpoint (#14083) * Adding pagination to query endpoint * Optimize the paging using Examine directly * Fix comment * Remove skip/take code duplication --------- Co-authored-by: kjac <kja@umbraco.dk> * Add missing CompatibilitySuppressions.xml * Make Delivery API packable * Make Api.Common packable * Renamed extension method and namespace so it is discoverable * Untangle ApiVersion configuration into api.common, so delivery api do not require the management api to boot. * configure options in management api * RTE output as JSON for Content API (#14067) * Conditionally serve RTE output as JSON instead of HTML * Fixed merge * Rename to Delivery API (#14119) * Rename ContentApi to DeliveryApi * Rename delivery API index implementation * Update comments from "Content API" to "Delivery API" * Rename project from Content to Delivery * Add dedicated controller base for content delivery API * Rename delivery API content index to include "content" specifically * Fix compat suppressions --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-04-19 11:21:31 +02:00
Mock.Of<IIOHelper>(),
Mock.Of<IEditorConfigurationParser>(),
Mock.Of<INestedContentPropertyIndexValueFactory>());
editors = new PropertyEditorCollection(new DataEditorCollection(() => new DataEditor[] { editor }));
2018-02-07 13:35:59 +01:00
var serializer = new ConfigurationEditorJsonSerializer();
var dataType1 = new DataType(editor, serializer)
{
Id = 1,
Configuration = new NestedContentConfiguration
2018-01-26 17:55:20 +01:00
{
MinItems = 1,
MaxItems = 1,
ContentTypes = new[] { new NestedContentConfiguration.ContentType { Alias = "contentN1" } },
},
};
2018-01-26 17:55:20 +01:00
var dataType2 = new DataType(editor, serializer)
{
Id = 2,
Configuration = new NestedContentConfiguration
2018-01-26 17:55:20 +01:00
{
MinItems = 1,
MaxItems = 99,
ContentTypes = new[] { new NestedContentConfiguration.ContentType { Alias = "contentN1" } },
},
};
var dataType3 =
new DataType(
new TextboxPropertyEditor(Mock.Of<IDataValueEditorFactory>(), Mock.Of<IIOHelper>(), Mock.Of<IEditorConfigurationParser>()), serializer)
{ Id = 3 };
// mocked dataservice returns nested content preValues
var dataTypeServiceMock = new Mock<IDataTypeService>();
dataTypeServiceMock.Setup(x => x.GetAll()).Returns(new[] { dataType1, dataType2, dataType3 });
var publishedModelFactory = new Mock<IPublishedModelFactory>();
// mocked model factory returns model type
var modelTypes = new Dictionary<string, Type> { { "contentN1", typeof(TestElementModel) } };
publishedModelFactory
.Setup(x => x.MapModelType(It.IsAny<Type>()))
.Returns((Type type) => ModelType.Map(type, modelTypes));
// mocked model factory creates models
publishedModelFactory
.Setup(x => x.CreateModel(It.IsAny<IPublishedElement>()))
.Returns((IPublishedElement element) =>
{
if (element.ContentType.Alias.InvariantEquals("contentN1"))
2018-01-26 17:55:20 +01:00
{
return new TestElementModel(element, Mock.Of<IPublishedValueFallback>());
2018-01-26 17:55:20 +01:00
}
2017-09-26 14:57:50 +02:00
return element;
2017-09-26 14:57:50 +02:00
});
// mocked model factory creates model lists
publishedModelFactory
.Setup(x => x.CreateModelList(It.IsAny<string>()))
.Returns((string alias) =>
alias == "contentN1"
? new List<TestElementModel>()
: new List<IPublishedElement>());
2017-10-17 17:43:15 +02:00
var contentCache = new Mock<IPublishedContentCache>();
var publishedSnapshot = new Mock<IPublishedSnapshot>();
2019-04-15 17:14:45 +02:00
// mocked published snapshot returns a content cache
publishedSnapshot
.Setup(x => x.Content)
.Returns(contentCache.Object);
2019-04-15 17:14:45 +02:00
var publishedSnapshotAccessor = new Mock<IPublishedSnapshotAccessor>();
2017-09-26 14:57:50 +02:00
// mocked published snapshot accessor returns a facade
var localPublishedSnapshot = publishedSnapshot.Object;
publishedSnapshotAccessor
.Setup(x => x.TryGetPublishedSnapshot(out localPublishedSnapshot))
.Returns(true);
2017-09-26 14:57:50 +02:00
var converters = new PropertyValueConverterCollection(() => new IPropertyValueConverter[]
{
Content Delivery API (#14051) * Add the core parts of the headless PoC * Add Content API project (WIP - loads of TODOs and dupes that need to be fixed!) * Rename the content API project and namespaces * Fixed bad merge * Rename everything "Headless" to "ContentApi" or "Api" * Refactor Content + Media: Key => Id, Name not nullable * Make Content API property return value types independent of datatype configuration * Clean up refactorings * First stab at an expansion strategy using content picker as example implementation * Use named JSON options for content API serialization * Proper inclusion and registration of the content API * Introduce API media builder * Make MNTP return API content/media depending on configuration (instead of links) and support output expansion * Content API: Get by controllers (#13740) * Adding ContentApiControllerBase * Adding get by id and url controllers * Change route of get all test controller * Rename to ContentApiController * Refactoring * Removing test controller * Content API: Add start-node header value to deal with url collisions (#13746) * Use start-node header value to deal with url collisions * Cleanup * Rename "url" param to "path" * Adding a start node service to get the start-node header value * Trim '/' from both beginning and end * Content API: Support Accept-Language header (#13831) * Move the content API JSON type resolver to an appropriate namespace * Add localization based on Accept-Language header * Content API: Output expansion (#13848) * Implement request based output expansion strategy + expansion output cache at property level * Slighty leaner implementation for default output expansion strategy * Clarify the code a bit * Fix bad merge * Encapsulate content API dependencies in the DI * Support multi-site and multi-culture routing + a little rename/refactor (#13882) * Support multi-site and multi-culture routing + a little rename/refactor * Make the by route controller handle root nodes * Rename Url to Path in API content output * Add a few comments for magic route creation * Rename services from "Default" to "Noop" * Ensure that Umbraco can boot without adding "AddContentApi()" to ConfigureServices * Moved incorrectly placed media builder * Fix API routes (#13915) * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Include umbraco properties (width, height, ...) in the Media Properties collection (#14023) * Move umbraco properties (width, height, ...) to the Properties collection of the API Media model * Don't output the umbracoFile property of media items * Add content type deny list (#14025) * Create a deny list of content types and utilize it for output generation * Add unit tests * Dedicated property cache level for Content API (#14027) * Support redirect tracking (#14033) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add cultures and their routes to the API output (#14038) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add culture routes to root output (for HREFLANG support) * Rename redirect service method to better match its purpose * Review changes * Delivery API: Query controller (#14041) * Initial commit * Custom ContentAPIFieldDefinitionCollection * Make index IUmbracoContentIndex * Add querying for children by parent id (key) * Add missing interface * Adding querying endpoint * Test code * Compose unpublishedValueSet, so that you get the correct data in the ContentAPI index * Renaming * Fix ancestorKeys index values * Adding IApiQueryExtensionService to be able to query the ContentAPI index in a generic way * Fix IApiQueryService and clean up QueryContentApiController using it * Support querying for path * Fix content API indexing * Fix default sorting * Implement concrete QueryOption implementations * Introduce new ExecuteQuery that uses the Core OptionHandlers * Implement ExecuteQuery * Change ExecuteQuery signature and implementation * Implement demo sorting and fetching * Add query option handlers and collection builder for them * Cleanup * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Test commit * Refactored interfaces for the query handlers and for the selectors (that will handle the value of the fetch query option) * Implemented a base class for the query options * Refactored the names of the selectors and made use of the base class * Refactored the ApiQueryService * Refactored the QueryContentApiController.cs * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Fixing merge gone wrong * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Make fetching work with the new setup * Moving files to dedicated folders * Removing ? for array * Rename selector query method * Implement FilterHandler and some filters * Implement SortHandler and sort some sorts * Refactoring * Adding more fields to index due to querying * Appending filtering and sorting queries * Implementing a new ISelectorHandler without Examine types * Re-implementing the collection to have a dedicated one for the selectors * Implementing a new IFilterHandler without Examine types & refactoring the filters implementing it * Adding a new collection dedicated to filters * Renaming the old collection * Implementing a new ISortHandler without Examine types & refactoring the sorts implementing it * Adding a new collection for the sorts & adding all collections to UmbracoBuilder.Collections * Refactoring the service to use the new collections and types * Refactoring the fields in ContentApiFieldDefinitionCollection * Remove nullability in Handlers * Don't return null for selector * Add TODO for having the filters support negation * Changing the SortType to FieldType with our custom types on the SortOption * Fix AncestorsSelector * Fix ApiQueryService * Documentation * Fix Swagger docs * Refactor the QueryContentApiController * Adding handling for the IApiContentResponse in the JsonTypeResolver * Refactor the service to use a safe fallback value in Examine queries * Adding Noop for the IApiQueryService * Cleanup * Remove comment * Fix name field for indexing * Don't inherit QueryOptionBase in filters * Fix casing for API index constant + swap FIXME with TODO * Add TODO for handling missing fetch with start-item header * Rename query handler parameters to not leak source (i.e. query string) --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa <> Co-authored-by: Zeegaan <nge@umbraco.dk> * Delivery API: Adding pagination to query endpoint (#14083) * Adding pagination to query endpoint * Optimize the paging using Examine directly * Fix comment * Remove skip/take code duplication --------- Co-authored-by: kjac <kja@umbraco.dk> * Add missing CompatibilitySuppressions.xml * Make Delivery API packable * Make Api.Common packable * Renamed extension method and namespace so it is discoverable * Untangle ApiVersion configuration into api.common, so delivery api do not require the management api to boot. * configure options in management api * RTE output as JSON for Content API (#14067) * Conditionally serve RTE output as JSON instead of HTML * Fixed merge * Rename to Delivery API (#14119) * Rename ContentApi to DeliveryApi * Rename delivery API index implementation * Update comments from "Content API" to "Delivery API" * Rename project from Content to Delivery * Add dedicated controller base for content delivery API * Rename delivery API content index to include "content" specifically * Fix compat suppressions --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-04-19 11:21:31 +02:00
new NestedContentSingleValueConverter(publishedSnapshotAccessor.Object, publishedModelFactory.Object, proflog, Mock.Of<IApiElementBuilder>()),
new NestedContentManyValueConverter(publishedSnapshotAccessor.Object, publishedModelFactory.Object, proflog, Mock.Of<IApiElementBuilder>()),
});
var factory =
new PublishedContentTypeFactory(publishedModelFactory.Object, converters, dataTypeServiceMock.Object);
IEnumerable<IPublishedPropertyType> CreatePropertyTypes1(IPublishedContentType contentType)
{
yield return factory.CreatePropertyType(contentType, "property1", 1);
}
2017-09-26 14:57:50 +02:00
IEnumerable<IPublishedPropertyType> CreatePropertyTypes2(IPublishedContentType contentType)
{
yield return factory.CreatePropertyType(contentType, "property2", 2);
2017-09-26 14:57:50 +02:00
}
IEnumerable<IPublishedPropertyType> CreatePropertyTypesN1(IPublishedContentType contentType)
2017-09-26 14:57:50 +02:00
{
yield return factory.CreatePropertyType(contentType, "propertyN1", 3);
}
2017-09-26 14:57:50 +02:00
var contentType1 = factory.CreateContentType(Guid.NewGuid(), 1, "content1", CreatePropertyTypes1);
var contentType2 = factory.CreateContentType(Guid.NewGuid(), 2, "content2", CreatePropertyTypes2);
var contentTypeN1 =
factory.CreateContentType(Guid.NewGuid(), 2, "contentN1", CreatePropertyTypesN1, isElement: true);
2017-09-26 14:57:50 +02:00
// mocked content cache returns content types
contentCache
.Setup(x => x.GetContentType(It.IsAny<string>()))
.Returns((string alias) =>
2017-09-26 14:57:50 +02:00
{
if (alias.InvariantEquals("contentN1"))
2019-06-07 11:15:58 +02:00
{
return contentTypeN1;
2019-06-07 11:15:58 +02:00
}
2017-09-26 14:57:50 +02:00
return null;
});
return (contentType1, contentType2);
}
[Test]
public void SingleNestedTest()
{
var (contentType1, _) = CreateContentTypes();
// nested single converter returns the proper value clr type TestModel, and cache level
Assert.AreEqual(typeof(TestElementModel), contentType1.GetPropertyType("property1").ClrType);
Assert.AreEqual(PropertyCacheLevel.Element, contentType1.GetPropertyType("property1").CacheLevel);
var key = Guid.NewGuid();
var keyA = Guid.NewGuid();
var content = new InternalPublishedContent(contentType1)
2017-09-26 14:57:50 +02:00
{
Key = key,
Properties = new[]
{
new TestPublishedProperty(
contentType1.GetPropertyType("property1"), $@"[
{{ ""key"": ""{keyA}"", ""propertyN1"": ""foo"", ""ncContentTypeAlias"": ""contentN1"" }}
]"),
},
};
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "property1");
// nested single converter returns proper TestModel value
Assert.IsInstanceOf<TestElementModel>(value);
var valueM = (TestElementModel)value;
Assert.AreEqual("foo", valueM.PropValue);
Assert.AreEqual(keyA, valueM.Key);
}
2017-09-26 14:57:50 +02:00
[Test]
public void ManyNestedTest()
{
var (_, contentType2) = CreateContentTypes();
// nested many converter returns the proper value clr type IEnumerable<TestModel>, and cache level
Assert.AreEqual(typeof(IEnumerable<TestElementModel>), contentType2.GetPropertyType("property2").ClrType);
Assert.AreEqual(PropertyCacheLevel.Element, contentType2.GetPropertyType("property2").CacheLevel);
2017-09-26 14:57:50 +02:00
var key = Guid.NewGuid();
var keyA = Guid.NewGuid();
var keyB = Guid.NewGuid();
var content = new InternalPublishedContent(contentType2)
{
Key = key,
Properties = new[]
2017-09-26 14:57:50 +02:00
{
new TestPublishedProperty(contentType2.GetPropertyType("property2"), $@"[
2017-09-26 14:57:50 +02:00
{{ ""key"": ""{keyA}"", ""propertyN1"": ""foo"", ""ncContentTypeAlias"": ""contentN1"" }},
{{ ""key"": ""{keyB}"", ""propertyN1"": ""bar"", ""ncContentTypeAlias"": ""contentN1"" }}
]"),
},
};
var value = content.Value(Mock.Of<IPublishedValueFallback>(), "property2");
// nested many converter returns proper IEnumerable<TestModel> value
Assert.IsInstanceOf<IEnumerable<IPublishedElement>>(value);
Assert.IsInstanceOf<IEnumerable<TestElementModel>>(value);
var valueM = ((IEnumerable<TestElementModel>)value).ToArray();
Assert.AreEqual("foo", valueM[0].PropValue);
Assert.AreEqual(keyA, valueM[0].Key);
Assert.AreEqual("bar", valueM[1].PropValue);
Assert.AreEqual(keyB, valueM[1].Key);
}
2017-09-26 14:57:50 +02:00
public class TestElementModel : PublishedElementModel
{
public TestElementModel(IPublishedElement content, IPublishedValueFallback fallback)
: base(content, fallback)
2017-09-26 14:57:50 +02:00
{
}
public string PropValue => this.Value<string>(Mock.Of<IPublishedValueFallback>(), "propertyN1");
}
2017-09-26 14:57:50 +02:00
public class TestPublishedProperty : PublishedPropertyBase
{
private readonly bool _hasValue;
private readonly bool _preview;
private readonly object _sourceValue;
private IPublishedElement _owner;
2017-09-26 14:57:50 +02:00
public TestPublishedProperty(IPublishedPropertyType propertyType, object source)
: base(propertyType, PropertyCacheLevel.Element) // initial reference cache level always is .Content
{
_sourceValue = source;
_hasValue = source != null && (!(source is string ssource) || !string.IsNullOrWhiteSpace(ssource));
}
2017-09-26 14:57:50 +02:00
public TestPublishedProperty(IPublishedPropertyType propertyType, IPublishedElement element, bool preview, PropertyCacheLevel referenceCacheLevel, object source)
: base(propertyType, referenceCacheLevel)
{
_sourceValue = source;
_hasValue = source != null && (!(source is string ssource) || !string.IsNullOrWhiteSpace(ssource));
_owner = element;
_preview = preview;
}
2017-09-26 14:57:50 +02:00
private object InterValue => PropertyType.ConvertSourceToInter(null, _sourceValue, false);
2017-09-26 14:57:50 +02:00
internal void SetOwner(IPublishedElement owner) => _owner = owner;
public override bool HasValue(string culture = null, string? segment = null) => _hasValue;
public override object GetSourceValue(string culture = null, string? segment = null) => _sourceValue;
public override object GetValue(string culture = null, string? segment = null) =>
PropertyType.ConvertInterToObject(_owner, ReferenceCacheLevel, InterValue, _preview);
public override object GetXPathValue(string culture = null, string? segment = null) =>
throw new InvalidOperationException("This method won't be implemented.");
Content Delivery API (#14051) * Add the core parts of the headless PoC * Add Content API project (WIP - loads of TODOs and dupes that need to be fixed!) * Rename the content API project and namespaces * Fixed bad merge * Rename everything "Headless" to "ContentApi" or "Api" * Refactor Content + Media: Key => Id, Name not nullable * Make Content API property return value types independent of datatype configuration * Clean up refactorings * First stab at an expansion strategy using content picker as example implementation * Use named JSON options for content API serialization * Proper inclusion and registration of the content API * Introduce API media builder * Make MNTP return API content/media depending on configuration (instead of links) and support output expansion * Content API: Get by controllers (#13740) * Adding ContentApiControllerBase * Adding get by id and url controllers * Change route of get all test controller * Rename to ContentApiController * Refactoring * Removing test controller * Content API: Add start-node header value to deal with url collisions (#13746) * Use start-node header value to deal with url collisions * Cleanup * Rename "url" param to "path" * Adding a start node service to get the start-node header value * Trim '/' from both beginning and end * Content API: Support Accept-Language header (#13831) * Move the content API JSON type resolver to an appropriate namespace * Add localization based on Accept-Language header * Content API: Output expansion (#13848) * Implement request based output expansion strategy + expansion output cache at property level * Slighty leaner implementation for default output expansion strategy * Clarify the code a bit * Fix bad merge * Encapsulate content API dependencies in the DI * Support multi-site and multi-culture routing + a little rename/refactor (#13882) * Support multi-site and multi-culture routing + a little rename/refactor * Make the by route controller handle root nodes * Rename Url to Path in API content output * Add a few comments for magic route creation * Rename services from "Default" to "Noop" * Ensure that Umbraco can boot without adding "AddContentApi()" to ConfigureServices * Moved incorrectly placed media builder * Fix API routes (#13915) * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Include umbraco properties (width, height, ...) in the Media Properties collection (#14023) * Move umbraco properties (width, height, ...) to the Properties collection of the API Media model * Don't output the umbracoFile property of media items * Add content type deny list (#14025) * Create a deny list of content types and utilize it for output generation * Add unit tests * Dedicated property cache level for Content API (#14027) * Support redirect tracking (#14033) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add cultures and their routes to the API output (#14038) * Create a deny list of content types and utilize it for output generation * Add unit tests * Handle redirect tracking in the content API * Include start item routing info for redirects * Add culture routes to root output (for HREFLANG support) * Rename redirect service method to better match its purpose * Review changes * Delivery API: Query controller (#14041) * Initial commit * Custom ContentAPIFieldDefinitionCollection * Make index IUmbracoContentIndex * Add querying for children by parent id (key) * Add missing interface * Adding querying endpoint * Test code * Compose unpublishedValueSet, so that you get the correct data in the ContentAPI index * Renaming * Fix ancestorKeys index values * Adding IApiQueryExtensionService to be able to query the ContentAPI index in a generic way * Fix IApiQueryService and clean up QueryContentApiController using it * Support querying for path * Fix content API indexing * Fix default sorting * Implement concrete QueryOption implementations * Introduce new ExecuteQuery that uses the Core OptionHandlers * Implement ExecuteQuery * Change ExecuteQuery signature and implementation * Implement demo sorting and fetching * Add query option handlers and collection builder for them * Cleanup * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Revert "Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992)" This reverts commit 78e1f748e55383baecd123d06457111e18f13365. * Revert "Delivery API: Content routing and structure (#13984)" This reverts commit a0292ae5350362dd6c1c5bc9763deda928c78a75. * Revert "Fix multi URL picker value converter trying to access disposed objects in edge cases" This reverts commit 6b7c37a5bf7871bee93a2b2640bbc6ef591f14db. * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Test commit * Refactored interfaces for the query handlers and for the selectors (that will handle the value of the fetch query option) * Implemented a base class for the query options * Refactored the names of the selectors and made use of the base class * Refactored the ApiQueryService * Refactored the QueryContentApiController.cs * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Fixing merge gone wrong * Fix multi URL picker value converter trying to access disposed objects in edge cases * Delivery API: Content routing and structure (#13984) * Introduce content route instead of content path, rename and rework start item (previously start node) handling * Strip out start node path in generated route path * Make the start-item header take precedence over the request domain * Conditionally enabling the delivery API + add protection and preview support + refactor all services to be singletons + ensure no-op implementations for all required services (#13992) * Make fetching work with the new setup * Moving files to dedicated folders * Removing ? for array * Rename selector query method * Implement FilterHandler and some filters * Implement SortHandler and sort some sorts * Refactoring * Adding more fields to index due to querying * Appending filtering and sorting queries * Implementing a new ISelectorHandler without Examine types * Re-implementing the collection to have a dedicated one for the selectors * Implementing a new IFilterHandler without Examine types & refactoring the filters implementing it * Adding a new collection dedicated to filters * Renaming the old collection * Implementing a new ISortHandler without Examine types & refactoring the sorts implementing it * Adding a new collection for the sorts & adding all collections to UmbracoBuilder.Collections * Refactoring the service to use the new collections and types * Refactoring the fields in ContentApiFieldDefinitionCollection * Remove nullability in Handlers * Don't return null for selector * Add TODO for having the filters support negation * Changing the SortType to FieldType with our custom types on the SortOption * Fix AncestorsSelector * Fix ApiQueryService * Documentation * Fix Swagger docs * Refactor the QueryContentApiController * Adding handling for the IApiContentResponse in the JsonTypeResolver * Refactor the service to use a safe fallback value in Examine queries * Adding Noop for the IApiQueryService * Cleanup * Remove comment * Fix name field for indexing * Don't inherit QueryOptionBase in filters * Fix casing for API index constant + swap FIXME with TODO * Add TODO for handling missing fetch with start-item header * Rename query handler parameters to not leak source (i.e. query string) --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa <> Co-authored-by: Zeegaan <nge@umbraco.dk> * Delivery API: Adding pagination to query endpoint (#14083) * Adding pagination to query endpoint * Optimize the paging using Examine directly * Fix comment * Remove skip/take code duplication --------- Co-authored-by: kjac <kja@umbraco.dk> * Add missing CompatibilitySuppressions.xml * Make Delivery API packable * Make Api.Common packable * Renamed extension method and namespace so it is discoverable * Untangle ApiVersion configuration into api.common, so delivery api do not require the management api to boot. * configure options in management api * RTE output as JSON for Content API (#14067) * Conditionally serve RTE output as JSON instead of HTML * Fixed merge * Rename to Delivery API (#14119) * Rename ContentApi to DeliveryApi * Rename delivery API index implementation * Update comments from "Content API" to "Delivery API" * Rename project from Content to Delivery * Add dedicated controller base for content delivery API * Rename delivery API content index to include "content" specifically * Fix compat suppressions --------- Co-authored-by: kjac <kja@umbraco.dk> Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Co-authored-by: Zeegaan <nge@umbraco.dk>
2023-04-19 11:21:31 +02:00
public override object GetDeliveryApiValue(bool expanding, string culture = null, string segment = null) =>
PropertyType.ConvertInterToDeliveryApiObject(_owner, ReferenceCacheLevel, InterValue, _preview, false);
2017-09-26 14:57:50 +02:00
}
}