2024-04-16 08:55:40 +02:00
|
|
|
using System.Collections.Concurrent;
|
2016-05-27 14:26:28 +02:00
|
|
|
using System.Xml.Serialization;
|
2021-02-18 11:06:02 +01:00
|
|
|
using Umbraco.Cms.Core.Cache;
|
|
|
|
|
using Umbraco.Cms.Core.Collections;
|
|
|
|
|
using Umbraco.Cms.Core.Models;
|
|
|
|
|
using Umbraco.Cms.Core.Models.PublishedContent;
|
|
|
|
|
using Umbraco.Cms.Core.PropertyEditors;
|
|
|
|
|
using Umbraco.Cms.Core.PublishedCache;
|
|
|
|
|
using Umbraco.Cms.Infrastructure.PublishedCache.DataSource;
|
|
|
|
|
using Umbraco.Extensions;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
namespace Umbraco.Cms.Infrastructure.PublishedCache;
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
[XmlType(Namespace = "http://umbraco.org/webservices/")]
|
|
|
|
|
internal class Property : PublishedPropertyBase
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
private readonly PublishedContent _content;
|
|
|
|
|
private readonly Guid _contentUid;
|
|
|
|
|
private readonly bool _isMember;
|
|
|
|
|
private readonly bool _isPreviewing;
|
|
|
|
|
|
|
|
|
|
private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor;
|
|
|
|
|
|
|
|
|
|
// the invariant-neutral source and inter values
|
|
|
|
|
private readonly object? _sourceValue;
|
|
|
|
|
private readonly ContentVariation _variations;
|
2024-05-13 15:44:07 +02:00
|
|
|
private readonly ContentVariation _sourceVariations;
|
2022-06-20 09:21:08 +02:00
|
|
|
|
|
|
|
|
// the variant and non-variant object values
|
|
|
|
|
private CacheValues? _cacheValues;
|
|
|
|
|
private bool _interInitialized;
|
|
|
|
|
private object? _interValue;
|
|
|
|
|
|
|
|
|
|
// the variant source and inter values
|
2024-04-16 08:55:40 +02:00
|
|
|
private readonly object _locko = new();
|
|
|
|
|
private ConcurrentDictionary<CompositeStringStringKey, SourceInterValue>? _sourceValues;
|
2022-06-20 09:21:08 +02:00
|
|
|
|
|
|
|
|
private string? _valuesCacheKey;
|
|
|
|
|
|
|
|
|
|
// initializes a published content property with no value
|
|
|
|
|
public Property(
|
|
|
|
|
IPublishedPropertyType propertyType,
|
|
|
|
|
PublishedContent content,
|
|
|
|
|
IPublishedSnapshotAccessor publishedSnapshotAccessor,
|
|
|
|
|
PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Element)
|
|
|
|
|
: this(propertyType, content, null, publishedSnapshotAccessor, referenceCacheLevel)
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
// initializes a published content property with a value
|
|
|
|
|
public Property(
|
|
|
|
|
IPublishedPropertyType propertyType,
|
|
|
|
|
PublishedContent content,
|
|
|
|
|
PropertyData[]? sourceValues,
|
|
|
|
|
IPublishedSnapshotAccessor publishedSnapshotAccessor,
|
|
|
|
|
PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Element)
|
|
|
|
|
: base(propertyType, referenceCacheLevel)
|
|
|
|
|
{
|
|
|
|
|
if (sourceValues != null)
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
foreach (PropertyData sourceValue in sourceValues)
|
2017-12-07 13:22:32 +01:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
if (sourceValue.Culture == string.Empty && sourceValue.Segment == string.Empty)
|
2017-12-07 13:22:32 +01:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
_sourceValue = sourceValue.Value;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-04-16 08:55:40 +02:00
|
|
|
EnsureSourceValuesInitialized();
|
2022-06-20 09:21:08 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
_sourceValues![new CompositeStringStringKey(sourceValue.Culture, sourceValue.Segment)]
|
2022-06-20 09:21:08 +02:00
|
|
|
= new SourceInterValue
|
|
|
|
|
{
|
|
|
|
|
Culture = sourceValue.Culture,
|
|
|
|
|
Segment = sourceValue.Segment,
|
|
|
|
|
SourceValue = sourceValue.Value,
|
|
|
|
|
};
|
2017-12-07 13:22:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
_contentUid = content.Key;
|
|
|
|
|
_content = content;
|
|
|
|
|
_isPreviewing = content.IsPreviewing;
|
|
|
|
|
_isMember = content.ContentType.ItemType == PublishedItemType.Member;
|
|
|
|
|
_publishedSnapshotAccessor = publishedSnapshotAccessor;
|
2023-09-25 13:45:28 +02:00
|
|
|
// this variable is used for contextualizing the variation level when calculating property values.
|
|
|
|
|
// it must be set to the union of variance (the combination of content type and property type variance).
|
|
|
|
|
_variations = propertyType.Variations | content.ContentType.Variations;
|
2024-05-13 15:44:07 +02:00
|
|
|
_sourceVariations = propertyType.Variations;
|
2022-06-20 09:21:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clone for previewing as draft a published content that is published and has no draft
|
|
|
|
|
public Property(Property origin, PublishedContent content)
|
|
|
|
|
: base(origin.PropertyType, origin.ReferenceCacheLevel)
|
|
|
|
|
{
|
|
|
|
|
_sourceValue = origin._sourceValue;
|
|
|
|
|
_sourceValues = origin._sourceValues;
|
|
|
|
|
|
|
|
|
|
_contentUid = origin._contentUid;
|
|
|
|
|
_content = content;
|
|
|
|
|
_isPreviewing = true;
|
|
|
|
|
_isMember = origin._isMember;
|
|
|
|
|
_publishedSnapshotAccessor = origin._publishedSnapshotAccessor;
|
|
|
|
|
_variations = origin._variations;
|
2024-05-13 15:44:07 +02:00
|
|
|
_sourceVariations = origin._sourceVariations;
|
2022-06-20 09:21:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// used to cache the CacheValues of this property
|
|
|
|
|
internal string ValuesCacheKey => _valuesCacheKey ??=
|
|
|
|
|
CacheKeys.PropertyCacheValues(_contentUid, Alias, _isPreviewing);
|
|
|
|
|
|
|
|
|
|
// determines whether a property has value
|
|
|
|
|
public override bool HasValue(string? culture = null, string? segment = null)
|
|
|
|
|
{
|
|
|
|
|
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
|
|
|
|
|
|
|
|
|
|
var value = GetSourceValue(culture, segment);
|
|
|
|
|
var hasValue = PropertyType.IsValue(value, PropertyValueLevel.Source);
|
|
|
|
|
if (hasValue.HasValue)
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
return hasValue.Value;
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
value = GetInterValue(culture, segment);
|
|
|
|
|
hasValue = PropertyType.IsValue(value, PropertyValueLevel.Inter);
|
|
|
|
|
if (hasValue.HasValue)
|
2018-05-08 11:06:07 +02:00
|
|
|
{
|
2024-04-16 08:55:40 +02:00
|
|
|
return hasValue.Value;
|
|
|
|
|
}
|
2018-07-19 11:02:51 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
CacheValue cacheValues = GetCacheValues(PropertyType.CacheLevel).For(culture, segment);
|
2018-07-19 11:02:51 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
// initial reference cache level always is .Content
|
|
|
|
|
const PropertyCacheLevel initialCacheLevel = PropertyCacheLevel.Element;
|
2022-06-20 09:21:08 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
if (!cacheValues.ObjectInitialized)
|
|
|
|
|
{
|
|
|
|
|
cacheValues.ObjectValue =
|
|
|
|
|
PropertyType.ConvertInterToObject(_content, initialCacheLevel, value, _isPreviewing);
|
|
|
|
|
cacheValues.ObjectInitialized = true;
|
2018-05-08 11:06:07 +02:00
|
|
|
}
|
2024-04-16 08:55:40 +02:00
|
|
|
|
|
|
|
|
value = cacheValues.ObjectValue;
|
|
|
|
|
return PropertyType.IsValue(value, PropertyValueLevel.Object) ?? false;
|
2022-06-20 09:21:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override object? GetSourceValue(string? culture = null, string? segment = null)
|
|
|
|
|
{
|
2024-05-13 15:44:07 +02:00
|
|
|
_content.VariationContextAccessor.ContextualizeVariation(_sourceVariations, _content.Id, ref culture, ref segment);
|
|
|
|
|
|
|
|
|
|
// source values are tightly bound to the property/schema culture and segment configurations, so we need to
|
|
|
|
|
// sanitize the contextualized culture/segment states before using them to access the source values.
|
|
|
|
|
culture = _sourceVariations.VariesByCulture() ? culture : string.Empty;
|
|
|
|
|
segment = _sourceVariations.VariesBySegment() ? segment : string.Empty;
|
2016-05-27 14:26:28 +02:00
|
|
|
|
2024-05-13 15:44:07 +02:00
|
|
|
if (culture == string.Empty && segment == string.Empty)
|
2022-06-20 09:21:08 +02:00
|
|
|
{
|
|
|
|
|
return _sourceValue;
|
|
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
if (_sourceValues == null)
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2024-04-16 08:55:40 +02:00
|
|
|
return null;
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|
2024-04-16 08:55:40 +02:00
|
|
|
|
|
|
|
|
return _sourceValues.TryGetValue(
|
|
|
|
|
new CompositeStringStringKey(culture, segment),
|
|
|
|
|
out SourceInterValue? sourceValue)
|
|
|
|
|
? sourceValue.SourceValue
|
|
|
|
|
: null;
|
2022-06-20 09:21:08 +02:00
|
|
|
}
|
2016-05-27 14:26:28 +02:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel)
|
|
|
|
|
{
|
|
|
|
|
CacheValues cacheValues;
|
|
|
|
|
IPublishedSnapshot publishedSnapshot;
|
|
|
|
|
IAppCache? cache;
|
|
|
|
|
switch (cacheLevel)
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
case PropertyCacheLevel.None:
|
|
|
|
|
// never cache anything
|
|
|
|
|
cacheValues = new CacheValues();
|
|
|
|
|
break;
|
|
|
|
|
case PropertyCacheLevel.Element:
|
|
|
|
|
// cache within the property object itself, ie within the content object
|
|
|
|
|
cacheValues = _cacheValues ??= new CacheValues();
|
|
|
|
|
break;
|
|
|
|
|
case PropertyCacheLevel.Elements:
|
|
|
|
|
// cache within the elements cache, unless previewing, then use the snapshot or
|
|
|
|
|
// elements cache (if we don't want to pollute the elements cache with short-lived
|
|
|
|
|
// data) depending on settings
|
|
|
|
|
// for members, always cache in the snapshot cache - never pollute elements cache
|
|
|
|
|
publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot();
|
|
|
|
|
cache = publishedSnapshot == null
|
|
|
|
|
? null
|
|
|
|
|
: (_isPreviewing == false || PublishedSnapshotService.FullCacheWhenPreviewing) && _isMember == false
|
|
|
|
|
? publishedSnapshot.ElementsCache
|
|
|
|
|
: publishedSnapshot.SnapshotCache;
|
|
|
|
|
cacheValues = GetCacheValues(cache);
|
|
|
|
|
break;
|
|
|
|
|
case PropertyCacheLevel.Snapshot:
|
|
|
|
|
// cache within the snapshot cache
|
|
|
|
|
publishedSnapshot = _publishedSnapshotAccessor.GetRequiredPublishedSnapshot();
|
|
|
|
|
cache = publishedSnapshot?.SnapshotCache;
|
|
|
|
|
cacheValues = GetCacheValues(cache);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw new InvalidOperationException("Invalid cache level.");
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
return cacheValues;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private CacheValues GetCacheValues(IAppCache? cache)
|
|
|
|
|
{
|
|
|
|
|
// no cache, don't cache
|
|
|
|
|
if (cache == null)
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
return new CacheValues();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (CacheValues)cache.Get(ValuesCacheKey, () => new CacheValues())!;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private object? GetInterValue(string? culture, string? segment)
|
|
|
|
|
{
|
|
|
|
|
if (culture == string.Empty && segment == string.Empty)
|
|
|
|
|
{
|
|
|
|
|
if (_interInitialized)
|
2017-12-07 13:22:32 +01:00
|
|
|
{
|
|
|
|
|
return _interValue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
_interValue = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing);
|
|
|
|
|
_interInitialized = true;
|
|
|
|
|
return _interValue;
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
EnsureSourceValuesInitialized();
|
2017-12-07 13:22:32 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
var k = new CompositeStringStringKey(culture, segment);
|
2024-04-16 08:55:40 +02:00
|
|
|
|
|
|
|
|
SourceInterValue vvalue = _sourceValues!.GetOrAdd(k, _ =>
|
|
|
|
|
new SourceInterValue
|
2017-12-07 13:22:32 +01:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
Culture = culture,
|
|
|
|
|
Segment = segment,
|
|
|
|
|
SourceValue = GetSourceValue(culture, segment),
|
2024-04-16 08:55:40 +02:00
|
|
|
});
|
2016-05-27 14:26:28 +02:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
if (vvalue.InterInitialized)
|
2016-05-27 14:26:28 +02:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
return vvalue.InterValue;
|
|
|
|
|
}
|
2018-04-18 19:46:47 +02:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
vvalue.InterValue = PropertyType.ConvertSourceToInter(_content, vvalue.SourceValue, _isPreviewing);
|
|
|
|
|
vvalue.InterInitialized = true;
|
|
|
|
|
return vvalue.InterValue;
|
|
|
|
|
}
|
2017-12-06 11:51:35 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
public override object? GetValue(string? culture = null, string? segment = null)
|
|
|
|
|
{
|
|
|
|
|
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
|
2017-12-27 15:10:52 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
object? value;
|
2024-04-16 08:55:40 +02:00
|
|
|
CacheValue cacheValues = GetCacheValues(PropertyType.CacheLevel).For(culture, segment);
|
2022-06-20 09:21:08 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
// initial reference cache level always is .Content
|
|
|
|
|
const PropertyCacheLevel initialCacheLevel = PropertyCacheLevel.Element;
|
2018-04-18 19:46:47 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
if (cacheValues.ObjectInitialized)
|
|
|
|
|
{
|
|
|
|
|
return cacheValues.ObjectValue;
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
cacheValues.ObjectValue = PropertyType.ConvertInterToObject(_content, initialCacheLevel, GetInterValue(culture, segment), _isPreviewing);
|
|
|
|
|
cacheValues.ObjectInitialized = true;
|
|
|
|
|
value = cacheValues.ObjectValue;
|
|
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
return value;
|
|
|
|
|
}
|
2018-04-18 19:46:47 +02:00
|
|
|
|
2023-07-07 11:12:04 +02:00
|
|
|
[Obsolete("The current implementation of XPath is suboptimal and will be removed entirely in a future version. Scheduled for removal in v14")]
|
2022-06-20 09:21:08 +02:00
|
|
|
public override object? GetXPathValue(string? culture = null, string? segment = null)
|
|
|
|
|
{
|
|
|
|
|
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
|
|
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
CacheValue cacheValues = GetCacheValues(PropertyType.CacheLevel).For(culture, segment);
|
2017-12-06 11:51:35 +01:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
// initial reference cache level always is .Content
|
|
|
|
|
const PropertyCacheLevel initialCacheLevel = PropertyCacheLevel.Element;
|
2017-12-27 15:10:52 +01:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
if (cacheValues.XPathInitialized)
|
|
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
return cacheValues.XPathValue;
|
2017-12-27 15:10:52 +01:00
|
|
|
}
|
2024-04-16 08:55:40 +02:00
|
|
|
|
|
|
|
|
cacheValues.XPathValue = PropertyType.ConvertInterToXPath(_content, initialCacheLevel, GetInterValue(culture, segment), _isPreviewing);
|
|
|
|
|
cacheValues.XPathInitialized = true;
|
|
|
|
|
return cacheValues.XPathValue;
|
2022-06-20 09:21:08 +02:00
|
|
|
}
|
2017-12-07 13:22:32 +01:00
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
_content.VariationContextAccessor.ContextualizeVariation(_variations, _content.Id, ref culture, ref segment);
|
|
|
|
|
|
|
|
|
|
object? value;
|
2024-04-16 08:55:40 +02:00
|
|
|
CacheValue cacheValues = GetCacheValues(expanding ? PropertyType.DeliveryApiCacheLevelForExpansion : PropertyType.DeliveryApiCacheLevel).For(culture, segment);
|
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
|
|
|
|
|
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
// initial reference cache level always is .Content
|
|
|
|
|
const PropertyCacheLevel initialCacheLevel = PropertyCacheLevel.Element;
|
|
|
|
|
|
|
|
|
|
object? GetDeliveryApiObject() => PropertyType.ConvertInterToDeliveryApiObject(_content, initialCacheLevel, GetInterValue(culture, segment), _isPreviewing, expanding);
|
|
|
|
|
value = expanding
|
|
|
|
|
? GetDeliveryApiExpandedObject(cacheValues, GetDeliveryApiObject)
|
|
|
|
|
: GetDeliveryApiDefaultObject(cacheValues, GetDeliveryApiObject);
|
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
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private object? GetDeliveryApiDefaultObject(CacheValue cacheValues, Func<object?> getValue)
|
|
|
|
|
{
|
|
|
|
|
if (cacheValues.DeliveryApiDefaultObjectInitialized == false)
|
|
|
|
|
{
|
|
|
|
|
cacheValues.DeliveryApiDefaultObjectValue = getValue();
|
|
|
|
|
cacheValues.DeliveryApiDefaultObjectInitialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cacheValues.DeliveryApiDefaultObjectValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private object? GetDeliveryApiExpandedObject(CacheValue cacheValues, Func<object?> getValue)
|
|
|
|
|
{
|
|
|
|
|
if (cacheValues.DeliveryApiExpandedObjectInitialized == false)
|
|
|
|
|
{
|
|
|
|
|
cacheValues.DeliveryApiExpandedObjectValue = getValue();
|
|
|
|
|
cacheValues.DeliveryApiExpandedObjectInitialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cacheValues.DeliveryApiExpandedObjectValue;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
#region Classes
|
2017-12-07 13:22:32 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
private class CacheValue
|
|
|
|
|
{
|
|
|
|
|
public bool ObjectInitialized { get; set; }
|
2017-12-07 13:22:32 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
public object? ObjectValue { get; set; }
|
2017-12-07 13:22:32 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
public bool XPathInitialized { get; set; }
|
2017-12-07 13:22:32 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
public object? XPathValue { get; set; }
|
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 bool DeliveryApiDefaultObjectInitialized { get; set; }
|
|
|
|
|
|
|
|
|
|
public object? DeliveryApiDefaultObjectValue { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool DeliveryApiExpandedObjectInitialized { get; set; }
|
|
|
|
|
|
|
|
|
|
public object? DeliveryApiExpandedObjectValue { get; set; }
|
2022-06-20 09:21:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class CacheValues : CacheValue
|
|
|
|
|
{
|
2024-04-16 08:55:40 +02:00
|
|
|
private readonly object _locko = new();
|
|
|
|
|
private ConcurrentDictionary<CompositeStringStringKey, CacheValue>? _values;
|
2017-12-07 13:22:32 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
public CacheValue For(string? culture, string? segment)
|
2017-12-07 13:22:32 +01:00
|
|
|
{
|
2022-06-20 09:21:08 +02:00
|
|
|
if (culture == string.Empty && segment == string.Empty)
|
|
|
|
|
{
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2017-12-27 15:10:52 +01:00
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
if (_values == null)
|
2018-04-21 09:57:28 +02:00
|
|
|
{
|
2024-04-16 08:55:40 +02:00
|
|
|
lock (_locko)
|
|
|
|
|
{
|
|
|
|
|
_values ??= InitializeConcurrentDictionary<CompositeStringStringKey, CacheValue>();
|
|
|
|
|
}
|
2018-04-21 09:57:28 +02:00
|
|
|
}
|
2022-06-20 09:21:08 +02:00
|
|
|
|
|
|
|
|
var k = new CompositeStringStringKey(culture, segment);
|
2024-04-16 08:55:40 +02:00
|
|
|
|
|
|
|
|
CacheValue value = _values.GetOrAdd(k, _ => new CacheValue());
|
2022-06-20 09:21:08 +02:00
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class SourceInterValue
|
|
|
|
|
{
|
|
|
|
|
private string? _culture;
|
|
|
|
|
private string? _segment;
|
|
|
|
|
|
|
|
|
|
public string? Culture
|
|
|
|
|
{
|
|
|
|
|
get => _culture;
|
|
|
|
|
internal set => _culture = value?.ToLowerInvariant();
|
2017-12-07 13:22:32 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
public string? Segment
|
|
|
|
|
{
|
|
|
|
|
get => _segment;
|
|
|
|
|
internal set => _segment = value?.ToLowerInvariant();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public object? SourceValue { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool InterInitialized { get; set; }
|
|
|
|
|
|
|
|
|
|
public object? InterValue { get; set; }
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|
2022-06-20 09:21:08 +02:00
|
|
|
|
2024-04-16 08:55:40 +02:00
|
|
|
private static ConcurrentDictionary<TKey, TValue> InitializeConcurrentDictionary<TKey, TValue>()
|
|
|
|
|
where TKey : notnull
|
|
|
|
|
=> new(-1, 5);
|
|
|
|
|
|
|
|
|
|
private void EnsureSourceValuesInitialized()
|
|
|
|
|
{
|
|
|
|
|
if (_sourceValues is not null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lock (_locko)
|
|
|
|
|
{
|
|
|
|
|
_sourceValues ??= InitializeConcurrentDictionary<CompositeStringStringKey, SourceInterValue>();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-20 09:21:08 +02:00
|
|
|
#endregion
|
2016-05-27 14:26:28 +02:00
|
|
|
}
|