Skip to content

Commit bbd3431

Browse files
kjacZeegaan
andcommitted
Fix various routing and preview issues for the Delivery API in V15 (#18036)
* Fix various routing and preview issues for the Delivery API in V15 * Fix breaking change in ctor * Fix ambigious constructors --------- Co-authored-by: Nikolaj Geisle <[email protected]>
1 parent 31fbd29 commit bbd3431

File tree

15 files changed

+491
-112
lines changed

15 files changed

+491
-112
lines changed

src/Umbraco.Cms.Api.Delivery/Querying/QueryOptionBase.cs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,51 @@
1+
using Microsoft.Extensions.DependencyInjection;
12
using Umbraco.Cms.Core.DeliveryApi;
2-
using Umbraco.Cms.Core.Models.PublishedContent;
3+
using Umbraco.Cms.Core.DependencyInjection;
34
using Umbraco.Cms.Core.PublishedCache;
45
using Umbraco.Extensions;
56

67
namespace Umbraco.Cms.Api.Delivery.Querying;
78

89
public abstract class QueryOptionBase
910
{
10-
private readonly IPublishedContentCache _publishedContentCache;
1111
private readonly IRequestRoutingService _requestRoutingService;
12+
private readonly IRequestPreviewService _requestPreviewService;
13+
private readonly IRequestCultureService _requestCultureService;
14+
private readonly IApiDocumentUrlService _apiDocumentUrlService;
1215

13-
16+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
1417
public QueryOptionBase(
1518
IPublishedContentCache publishedContentCache,
1619
IRequestRoutingService requestRoutingService)
20+
: this(
21+
requestRoutingService,
22+
StaticServiceProvider.Instance.GetRequiredService<IRequestPreviewService>(),
23+
StaticServiceProvider.Instance.GetRequiredService<IRequestCultureService>(),
24+
StaticServiceProvider.Instance.GetRequiredService<IApiDocumentUrlService>())
25+
{
26+
}
27+
28+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
29+
public QueryOptionBase(
30+
IPublishedContentCache publishedContentCache,
31+
IRequestRoutingService requestRoutingService,
32+
IRequestPreviewService requestPreviewService,
33+
IRequestCultureService requestCultureService,
34+
IApiDocumentUrlService apiDocumentUrlService)
35+
: this(requestRoutingService, requestPreviewService, requestCultureService, apiDocumentUrlService)
36+
{
37+
}
38+
39+
public QueryOptionBase(
40+
IRequestRoutingService requestRoutingService,
41+
IRequestPreviewService requestPreviewService,
42+
IRequestCultureService requestCultureService,
43+
IApiDocumentUrlService apiDocumentUrlService)
1744
{
18-
_publishedContentCache = publishedContentCache;
1945
_requestRoutingService = requestRoutingService;
46+
_requestPreviewService = requestPreviewService;
47+
_requestCultureService = requestCultureService;
48+
_apiDocumentUrlService = apiDocumentUrlService;
2049
}
2150

2251
protected Guid? GetGuidFromQuery(string queryStringValue)
@@ -33,8 +62,9 @@ public QueryOptionBase(
3362

3463
// Check if the passed value is a path of a content item
3564
var contentRoute = _requestRoutingService.GetContentRoute(queryStringValue);
36-
IPublishedContent? contentItem = _publishedContentCache.GetByRoute(contentRoute);
37-
38-
return contentItem?.Key;
65+
return _apiDocumentUrlService.GetDocumentKeyByRoute(
66+
contentRoute,
67+
_requestCultureService.GetRequestedCulture(),
68+
_requestPreviewService.IsPreview());
3969
}
4070
}

src/Umbraco.Cms.Api.Delivery/Querying/Selectors/AncestorsSelector.cs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,77 @@
22
using Umbraco.Cms.Api.Delivery.Indexing.Selectors;
33
using Umbraco.Cms.Core.DeliveryApi;
44
using Umbraco.Cms.Core.DependencyInjection;
5-
using Umbraco.Cms.Core.Models.PublishedContent;
65
using Umbraco.Cms.Core.PublishedCache;
76
using Umbraco.Cms.Core.Services.Navigation;
8-
using Umbraco.Extensions;
97

108
namespace Umbraco.Cms.Api.Delivery.Querying.Selectors;
119

1210
public sealed class AncestorsSelector : QueryOptionBase, ISelectorHandler
1311
{
14-
private readonly IPublishedContentCache _publishedContentCache;
1512
private readonly IDocumentNavigationQueryService _navigationQueryService;
16-
private readonly IRequestPreviewService _requestPreviewService;
1713
private const string AncestorsSpecifier = "ancestors:";
1814

15+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
1916
public AncestorsSelector(
2017
IPublishedContentCache publishedContentCache,
2118
IRequestRoutingService requestRoutingService,
2219
IDocumentNavigationQueryService navigationQueryService,
2320
IRequestPreviewService requestPreviewService)
24-
: base(publishedContentCache, requestRoutingService)
21+
: this(
22+
requestRoutingService,
23+
StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>(),
24+
StaticServiceProvider.Instance.GetRequiredService<IRequestPreviewService>(),
25+
StaticServiceProvider.Instance.GetRequiredService<IRequestCultureService>(),
26+
StaticServiceProvider.Instance.GetRequiredService<IApiDocumentUrlService>(),
27+
navigationQueryService)
2528
{
26-
_publishedContentCache = publishedContentCache;
27-
_navigationQueryService = navigationQueryService;
28-
_requestPreviewService = requestPreviewService;
2929
}
3030

31-
[Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
31+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
3232
public AncestorsSelector(
3333
IPublishedContentCache publishedContentCache,
3434
IRequestRoutingService requestRoutingService,
3535
IDocumentNavigationQueryService navigationQueryService)
36-
: this(publishedContentCache, requestRoutingService, navigationQueryService, StaticServiceProvider.Instance.GetRequiredService<IRequestPreviewService>())
36+
: this(
37+
requestRoutingService,
38+
StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>(),
39+
StaticServiceProvider.Instance.GetRequiredService<IRequestPreviewService>(),
40+
StaticServiceProvider.Instance.GetRequiredService<IRequestCultureService>(),
41+
StaticServiceProvider.Instance.GetRequiredService<IApiDocumentUrlService>(),
42+
navigationQueryService)
3743
{
3844
}
3945

4046
[Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
4147
public AncestorsSelector(IPublishedContentCache publishedContentCache, IRequestRoutingService requestRoutingService)
42-
: this(publishedContentCache, requestRoutingService, StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>())
48+
: this(
49+
requestRoutingService,
50+
StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>(),
51+
StaticServiceProvider.Instance.GetRequiredService<IRequestPreviewService>(),
52+
StaticServiceProvider.Instance.GetRequiredService<IRequestCultureService>(),
53+
StaticServiceProvider.Instance.GetRequiredService<IApiDocumentUrlService>(),
54+
StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>())
55+
{
56+
}
57+
58+
public AncestorsSelector(
59+
IRequestRoutingService requestRoutingService,
60+
IRequestPreviewService requestPreviewService,
61+
IRequestCultureService requestCultureService,
62+
IApiDocumentUrlService apiDocumentUrlService,
63+
IDocumentNavigationQueryService navigationQueryService)
64+
: base(requestRoutingService, requestPreviewService, requestCultureService, apiDocumentUrlService)
65+
=> _navigationQueryService = navigationQueryService;
66+
67+
[Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
68+
public AncestorsSelector(
69+
IRequestRoutingService requestRoutingService,
70+
IPublishedContentCache publishedContentCache,
71+
IRequestPreviewService requestPreviewService,
72+
IRequestCultureService requestCultureService,
73+
IApiDocumentUrlService apiDocumentUrlService,
74+
IDocumentNavigationQueryService navigationQueryService)
75+
: this(requestRoutingService, requestPreviewService, requestCultureService, apiDocumentUrlService, navigationQueryService)
4376
{
4477
}
4578

@@ -53,7 +86,7 @@ public SelectorOption BuildSelectorOption(string selector)
5386
var fieldValue = selector[AncestorsSpecifier.Length..];
5487
Guid? id = GetGuidFromQuery(fieldValue);
5588

56-
if (id is null)
89+
if (id is null || _navigationQueryService.TryGetAncestorsKeys(id.Value, out IEnumerable<Guid> ancestorKeys) is false)
5790
{
5891
// Setting the Value to "" since that would yield no results.
5992
// It won't be appropriate to return null here since if we reached this,
@@ -65,24 +98,10 @@ public SelectorOption BuildSelectorOption(string selector)
6598
};
6699
}
67100

68-
IPublishedContent? contentItem = _publishedContentCache.GetById(_requestPreviewService.IsPreview(), id.Value);
69-
70-
if (contentItem is null)
71-
{
72-
// no such content item, make sure the selector does not yield any results
73-
return new SelectorOption
74-
{
75-
FieldName = AncestorsSelectorIndexer.FieldName,
76-
Values = Array.Empty<string>()
77-
};
78-
}
79-
80-
var ancestorKeys = contentItem.Ancestors(_publishedContentCache, _navigationQueryService).Select(a => a.Key.ToString("D")).ToArray();
81-
82101
return new SelectorOption
83102
{
84103
FieldName = AncestorsSelectorIndexer.FieldName,
85-
Values = ancestorKeys
104+
Values = ancestorKeys.Select(key => key.ToString("D")).ToArray()
86105
};
87106
}
88107
}

src/Umbraco.Cms.Api.Delivery/Querying/Selectors/ChildrenSelector.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using Microsoft.Extensions.DependencyInjection;
12
using Umbraco.Cms.Api.Delivery.Indexing.Selectors;
23
using Umbraco.Cms.Core.DeliveryApi;
4+
using Umbraco.Cms.Core.DependencyInjection;
35
using Umbraco.Cms.Core.PublishedCache;
46
using Umbraco.Extensions;
57

@@ -9,8 +11,33 @@ public sealed class ChildrenSelector : QueryOptionBase, ISelectorHandler
911
{
1012
private const string ChildrenSpecifier = "children:";
1113

14+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
1215
public ChildrenSelector(IPublishedContentCache publishedContentCache, IRequestRoutingService requestRoutingService)
13-
: base(publishedContentCache, requestRoutingService)
16+
: this(
17+
requestRoutingService,
18+
StaticServiceProvider.Instance.GetRequiredService<IRequestPreviewService>(),
19+
StaticServiceProvider.Instance.GetRequiredService<IRequestCultureService>(),
20+
StaticServiceProvider.Instance.GetRequiredService<IApiDocumentUrlService>())
21+
{
22+
}
23+
24+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
25+
public ChildrenSelector(
26+
IPublishedContentCache publishedContentCache,
27+
IRequestRoutingService requestRoutingService,
28+
IRequestPreviewService requestPreviewService,
29+
IRequestCultureService requestCultureService,
30+
IApiDocumentUrlService apiDocumentUrlService)
31+
: this(requestRoutingService, requestPreviewService, requestCultureService, apiDocumentUrlService)
32+
{
33+
}
34+
35+
public ChildrenSelector(
36+
IRequestRoutingService requestRoutingService,
37+
IRequestPreviewService requestPreviewService,
38+
IRequestCultureService requestCultureService,
39+
IApiDocumentUrlService apiDocumentUrlService)
40+
: base(requestRoutingService, requestPreviewService, requestCultureService, apiDocumentUrlService)
1441
{
1542
}
1643

src/Umbraco.Cms.Api.Delivery/Querying/Selectors/DescendantsSelector.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using Microsoft.Extensions.DependencyInjection;
12
using Umbraco.Cms.Api.Delivery.Indexing.Selectors;
23
using Umbraco.Cms.Core.DeliveryApi;
4+
using Umbraco.Cms.Core.DependencyInjection;
35
using Umbraco.Cms.Core.PublishedCache;
46
using Umbraco.Extensions;
57

@@ -9,8 +11,33 @@ public sealed class DescendantsSelector : QueryOptionBase, ISelectorHandler
911
{
1012
private const string DescendantsSpecifier = "descendants:";
1113

14+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
1215
public DescendantsSelector(IPublishedContentCache publishedContentCache, IRequestRoutingService requestRoutingService)
13-
: base(publishedContentCache, requestRoutingService)
16+
: this(
17+
requestRoutingService,
18+
StaticServiceProvider.Instance.GetRequiredService<IRequestPreviewService>(),
19+
StaticServiceProvider.Instance.GetRequiredService<IRequestCultureService>(),
20+
StaticServiceProvider.Instance.GetRequiredService<IApiDocumentUrlService>())
21+
{
22+
}
23+
24+
[Obsolete("Please use the non-obsolete constructor. Will be removed in V17.")]
25+
public DescendantsSelector(
26+
IPublishedContentCache publishedContentCache,
27+
IRequestRoutingService requestRoutingService,
28+
IRequestPreviewService requestPreviewService,
29+
IRequestCultureService requestCultureService,
30+
IApiDocumentUrlService apiDocumentUrlService)
31+
: this(requestRoutingService, requestPreviewService, requestCultureService, apiDocumentUrlService)
32+
{
33+
}
34+
35+
public DescendantsSelector(
36+
IRequestRoutingService requestRoutingService,
37+
IRequestPreviewService requestPreviewService,
38+
IRequestCultureService requestCultureService,
39+
IApiDocumentUrlService apiDocumentUrlService)
40+
: base(requestRoutingService, requestPreviewService, requestCultureService, apiDocumentUrlService)
1441
{
1542
}
1643

src/Umbraco.Cms.Api.Delivery/Services/RequestStartItemProvider.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,8 @@ public RequestStartItemProvider(
4949

5050
_documentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
5151
IEnumerable<IPublishedContent> rootContent = rootKeys
52-
.Select(_publishedContentCache.GetById)
53-
.WhereNotNull()
54-
.Where(x => x.IsPublished() != _requestPreviewService.IsPreview());
52+
.Select(rootKey => _publishedContentCache.GetById(_requestPreviewService.IsPreview(), rootKey))
53+
.WhereNotNull();
5554

5655
_requestedStartContent = Guid.TryParse(headerValue, out Guid key)
5756
? rootContent.FirstOrDefault(c => c.Key == key)

src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public ApiContentRouteBuilder(
9595
{
9696
// entirely unpublished content does not resolve any route, but we need one i.e. for preview to work,
9797
// so we'll use the content key as path.
98-
if (isPreview && content.IsPublished(culture) is false)
98+
if (isPreview && _publishStatusQueryService.IsDocumentPublished(content.Key, culture ?? string.Empty) is false)
9999
{
100100
return ContentPreviewPath(content);
101101
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Umbraco.Cms.Core.Services;
2+
using Umbraco.Extensions;
3+
4+
namespace Umbraco.Cms.Core.DeliveryApi;
5+
6+
public sealed class ApiDocumentUrlService : IApiDocumentUrlService
7+
{
8+
private readonly IDocumentUrlService _documentUrlService;
9+
10+
public ApiDocumentUrlService(IDocumentUrlService documentUrlService)
11+
=> _documentUrlService = documentUrlService;
12+
13+
public Guid? GetDocumentKeyByRoute(string route, string? culture, bool preview)
14+
{
15+
// Handle the nasty logic with domain document ids in front of paths.
16+
int? documentStartNodeId = null;
17+
if (route.StartsWith('/') is false)
18+
{
19+
var index = route.IndexOf('/');
20+
21+
if (index > -1 && int.TryParse(route.Substring(0, index), out var nodeId))
22+
{
23+
documentStartNodeId = nodeId;
24+
route = route.Substring(index);
25+
}
26+
}
27+
28+
return _documentUrlService.GetDocumentKeyByRoute(
29+
route,
30+
culture.NullOrWhiteSpaceAsNull(),
31+
documentStartNodeId,
32+
preview);
33+
}
34+
}

0 commit comments

Comments
 (0)