Skip to content

Commit cd25c9a

Browse files
committed
Merge branch 'release/15.1.1' into v15/dev
# Conflicts: # src/Umbraco.Core/Extensions/PublishedContentExtensions.cs # src/Umbraco.Web.UI.Client/package-lock.json # src/Umbraco.Web.UI.Client/package.json # version.json
2 parents 0920019 + 4f3dd04 commit cd25c9a

File tree

105 files changed

+2761
-564
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+2761
-564
lines changed

src/Umbraco.Cms.Api.Management/Controllers/Document/GetPublicAccessDocumentController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public async Task<IActionResult> GetPublicAccess(CancellationToken cancellationT
4949
}
5050

5151
Attempt<PublicAccessEntry?, PublicAccessOperationStatus> accessAttempt =
52-
await _publicAccessService.GetEntryByContentKeyAsync(id);
52+
await _publicAccessService.GetEntryByContentKeyWithoutAncestorsAsync(id);
5353

5454
if (accessAttempt.Success is false || accessAttempt.Result is null)
5555
{

src/Umbraco.Core/DeliveryApi/ApiContentRouteBuilder.cs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using Microsoft.Extensions.Options;
1+
using Microsoft.Extensions.DependencyInjection;
2+
using Microsoft.Extensions.Options;
23
using Umbraco.Cms.Core.Configuration.Models;
4+
using Umbraco.Cms.Core.DependencyInjection;
35
using Umbraco.Cms.Core.Models.DeliveryApi;
46
using Umbraco.Cms.Core.Models.PublishedContent;
57
using Umbraco.Cms.Core.PublishedCache;
@@ -16,6 +18,7 @@ public sealed class ApiContentRouteBuilder : IApiContentRouteBuilder
1618
private readonly IRequestPreviewService _requestPreviewService;
1719
private readonly IPublishedContentCache _contentCache;
1820
private readonly IDocumentNavigationQueryService _navigationQueryService;
21+
private readonly IPublishStatusQueryService _publishStatusQueryService;
1922
private RequestHandlerSettings _requestSettings;
2023

2124
public ApiContentRouteBuilder(
@@ -25,18 +28,41 @@ public ApiContentRouteBuilder(
2528
IRequestPreviewService requestPreviewService,
2629
IOptionsMonitor<RequestHandlerSettings> requestSettings,
2730
IPublishedContentCache contentCache,
28-
IDocumentNavigationQueryService navigationQueryService)
31+
IDocumentNavigationQueryService navigationQueryService,
32+
IPublishStatusQueryService publishStatusQueryService)
2933
{
3034
_apiContentPathProvider = apiContentPathProvider;
3135
_variationContextAccessor = variationContextAccessor;
3236
_requestPreviewService = requestPreviewService;
3337
_contentCache = contentCache;
3438
_navigationQueryService = navigationQueryService;
39+
_publishStatusQueryService = publishStatusQueryService;
3540
_globalSettings = globalSettings.Value;
3641
_requestSettings = requestSettings.CurrentValue;
3742
requestSettings.OnChange(settings => _requestSettings = settings);
3843
}
3944

45+
[Obsolete("Use constructor that takes an IPublishStatusQueryService instead, scheduled for removal in v17")]
46+
public ApiContentRouteBuilder(
47+
IApiContentPathProvider apiContentPathProvider,
48+
IOptions<GlobalSettings> globalSettings,
49+
IVariationContextAccessor variationContextAccessor,
50+
IRequestPreviewService requestPreviewService,
51+
IOptionsMonitor<RequestHandlerSettings> requestSettings,
52+
IPublishedContentCache contentCache,
53+
IDocumentNavigationQueryService navigationQueryService)
54+
: this(
55+
apiContentPathProvider,
56+
globalSettings,
57+
variationContextAccessor,
58+
requestPreviewService,
59+
requestSettings,
60+
contentCache,
61+
navigationQueryService,
62+
StaticServiceProvider.Instance.GetRequiredService<IPublishStatusQueryService>())
63+
{
64+
}
65+
4066
public IApiContentRoute? Build(IPublishedContent content, string? culture = null)
4167
{
4268
if (content.ItemType != PublishedItemType.Content)
@@ -105,7 +131,7 @@ private IPublishedContent GetRoot(IPublishedContent content, bool isPreview)
105131
{
106132
if (isPreview is false)
107133
{
108-
return content.Root(_contentCache, _navigationQueryService);
134+
return content.Root(_variationContextAccessor, _contentCache, _navigationQueryService, _publishStatusQueryService);
109135
}
110136

111137
_navigationQueryService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
@@ -114,6 +140,6 @@ private IPublishedContent GetRoot(IPublishedContent content, bool isPreview)
114140
// in very edge case scenarios during preview, content.Root() does not map to the root.
115141
// we'll code our way around it for the time being.
116142
return rootContent.FirstOrDefault(root => root.IsAncestorOrSelf(content))
117-
?? content.Root(_contentCache, _navigationQueryService);
143+
?? content.Root(_variationContextAccessor, _contentCache, _navigationQueryService, _publishStatusQueryService);
118144
}
119145
}

src/Umbraco.Core/Extensions/PublishedContentExtensions.cs

Lines changed: 2266 additions & 304 deletions
Large diffs are not rendered by default.

src/Umbraco.Core/Routing/ContentFinderByUrlAlias.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using Microsoft.Extensions.DependencyInjection;
12
using Microsoft.Extensions.Logging;
3+
using Umbraco.Cms.Core.DependencyInjection;
24
using Umbraco.Cms.Core.Models.PublishedContent;
35
using Umbraco.Cms.Core.PublishedCache;
46
using Umbraco.Cms.Core.Services.Navigation;
@@ -24,6 +26,7 @@ public class ContentFinderByUrlAlias : IContentFinder
2426
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
2527
private readonly IPublishedContentCache _contentCache;
2628
private readonly IDocumentNavigationQueryService _documentNavigationQueryService;
29+
private readonly IPublishStatusQueryService _publishStatusQueryService;
2730
private readonly IVariationContextAccessor _variationContextAccessor;
2831

2932
/// <summary>
@@ -35,16 +38,37 @@ public ContentFinderByUrlAlias(
3538
IVariationContextAccessor variationContextAccessor,
3639
IUmbracoContextAccessor umbracoContextAccessor,
3740
IPublishedContentCache contentCache,
38-
IDocumentNavigationQueryService documentNavigationQueryService)
41+
IDocumentNavigationQueryService documentNavigationQueryService,
42+
IPublishStatusQueryService publishStatusQueryService)
3943
{
4044
_publishedValueFallback = publishedValueFallback;
4145
_variationContextAccessor = variationContextAccessor;
4246
_umbracoContextAccessor = umbracoContextAccessor;
4347
_contentCache = contentCache;
4448
_documentNavigationQueryService = documentNavigationQueryService;
49+
_publishStatusQueryService = publishStatusQueryService;
4550
_logger = logger;
4651
}
4752

53+
[Obsolete("Please use constructor that takes an IPublishStatusQueryService instead. Scheduled removal in v17")]
54+
public ContentFinderByUrlAlias(
55+
ILogger<ContentFinderByUrlAlias> logger,
56+
IPublishedValueFallback publishedValueFallback,
57+
IVariationContextAccessor variationContextAccessor,
58+
IUmbracoContextAccessor umbracoContextAccessor,
59+
IPublishedContentCache contentCache,
60+
IDocumentNavigationQueryService documentNavigationQueryService)
61+
: this(
62+
logger,
63+
publishedValueFallback,
64+
variationContextAccessor,
65+
umbracoContextAccessor,
66+
contentCache,
67+
documentNavigationQueryService,
68+
StaticServiceProvider.Instance.GetRequiredService<IPublishStatusQueryService>())
69+
{
70+
}
71+
4872
/// <summary>
4973
/// Tries to find and assign an Umbraco document to a <c>PublishedRequest</c>.
5074
/// </summary>
@@ -145,14 +169,14 @@ bool IsMatch(IPublishedContent c, string a1, string a2)
145169
if (rootNodeId > 0)
146170
{
147171
IPublishedContent? rootNode = cache?.GetById(rootNodeId);
148-
return rootNode?.Descendants(_variationContextAccessor, _contentCache, _documentNavigationQueryService).FirstOrDefault(x => IsMatch(x, test1, test2));
172+
return rootNode?.Descendants(_variationContextAccessor, _contentCache, _documentNavigationQueryService, _publishStatusQueryService).FirstOrDefault(x => IsMatch(x, test1, test2));
149173
}
150174

151175
if (cache is not null)
152176
{
153177
foreach (IPublishedContent rootContent in cache.GetAtRoot())
154178
{
155-
IPublishedContent? c = rootContent.DescendantsOrSelf(_variationContextAccessor, _contentCache, _documentNavigationQueryService)
179+
IPublishedContent? c = rootContent.DescendantsOrSelf(_variationContextAccessor, _contentCache, _documentNavigationQueryService, _publishStatusQueryService)
156180
.FirstOrDefault(x => IsMatch(x, test1, test2));
157181
if (c != null)
158182
{

src/Umbraco.Core/Routing/UrlProvider.cs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,48 @@ public class UrlProvider : IPublishedUrlProvider
2727
/// <param name="variationContextAccessor">The current variation accessor.</param>
2828
/// <param name="contentCache">The content cache.</param>
2929
/// <param name="navigationQueryService">The query service for the in-memory navigation structure.</param>
30+
/// <param name="publishStatusQueryService">The publish status query service, to query if a given content is published in a given culture.</param>
3031
public UrlProvider(
3132
IUmbracoContextAccessor umbracoContextAccessor,
3233
IOptions<WebRoutingSettings> routingSettings,
3334
UrlProviderCollection urlProviders,
3435
MediaUrlProviderCollection mediaUrlProviders,
3536
IVariationContextAccessor variationContextAccessor,
3637
IPublishedContentCache contentCache,
37-
IDocumentNavigationQueryService navigationQueryService)
38+
IDocumentNavigationQueryService navigationQueryService,
39+
IPublishStatusQueryService publishStatusQueryService)
3840
{
3941
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
4042
_urlProviders = urlProviders;
4143
_mediaUrlProviders = mediaUrlProviders;
4244
_variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor));
4345
_contentCache = contentCache;
4446
_navigationQueryService = navigationQueryService;
47+
_publishStatusQueryService = publishStatusQueryService;
4548
Mode = routingSettings.Value.UrlProviderMode;
4649
}
4750

51+
[Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
52+
public UrlProvider(
53+
IUmbracoContextAccessor umbracoContextAccessor,
54+
IOptions<WebRoutingSettings> routingSettings,
55+
UrlProviderCollection urlProviders,
56+
MediaUrlProviderCollection mediaUrlProviders,
57+
IVariationContextAccessor variationContextAccessor,
58+
IPublishedContentCache contentCache,
59+
IDocumentNavigationQueryService navigationQueryService)
60+
: this(
61+
umbracoContextAccessor,
62+
routingSettings,
63+
urlProviders,
64+
mediaUrlProviders,
65+
variationContextAccessor,
66+
contentCache,
67+
navigationQueryService,
68+
StaticServiceProvider.Instance.GetRequiredService<IPublishStatusQueryService>())
69+
{
70+
}
71+
4872
[Obsolete("Use the constructor that takes all parameters. Scheduled for removal in V17.")]
4973
public UrlProvider(
5074
IUmbracoContextAccessor umbracoContextAccessor,
@@ -59,7 +83,8 @@ public UrlProvider(
5983
mediaUrlProviders,
6084
variationContextAccessor,
6185
StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>(),
62-
StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>())
86+
StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>(),
87+
StaticServiceProvider.Instance.GetRequiredService<IPublishStatusQueryService>())
6388
{
6489
}
6590

@@ -69,6 +94,7 @@ public UrlProvider(
6994
private readonly IVariationContextAccessor _variationContextAccessor;
7095
private readonly IPublishedContentCache _contentCache;
7196
private readonly IDocumentNavigationQueryService _navigationQueryService;
97+
private readonly IPublishStatusQueryService _publishStatusQueryService;
7298

7399
/// <summary>
74100
/// Gets or sets the provider URL mode.
@@ -147,7 +173,7 @@ public string GetUrl(IPublishedContent? content, UrlMode mode = UrlMode.Default,
147173
// be nice with tests, assume things can be null, ultimately fall back to invariant
148174
// (but only for variant content of course)
149175
// We need to check all ancestors because urls are variant even for invariant content, if an ancestor is variant.
150-
if (culture == null && content.AncestorsOrSelf(_contentCache, _navigationQueryService).Any(x => x.ContentType.VariesByCulture()))
176+
if (culture == null && content.AncestorsOrSelf(_variationContextAccessor, _contentCache, _navigationQueryService, _publishStatusQueryService).Any(x => x.ContentType.VariesByCulture()))
151177
{
152178
culture = _variationContextAccessor?.VariationContext?.Culture ?? string.Empty;
153179
}

src/Umbraco.Core/Services/DomainService.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,17 @@ private IDomain[] CalculateNewAssignedDomains(int contentId, DomainsUpdateModel
311311
var sortOrder = 0;
312312
foreach (DomainModel domainModel in updateModel.Domains)
313313
{
314-
IDomain assignedDomain = currentlyAssignedDomains.FirstOrDefault(domain => domainModel.DomainName.InvariantEquals(domain.DomainName))
315-
?? new UmbracoDomain(domainModel.DomainName)
316-
{
317-
LanguageId = languageIdByIsoCode[domainModel.IsoCode],
318-
RootContentId = contentId
319-
};
314+
IDomain? assignedDomain = currentlyAssignedDomains.FirstOrDefault(domain => domainModel.DomainName.InvariantEquals(domain.DomainName));
315+
316+
// If we do not have an assigned domain, or the domain-language has been changed, create new domain.
317+
if (assignedDomain is null || assignedDomain.LanguageId != languageIdByIsoCode[domainModel.IsoCode])
318+
{
319+
assignedDomain = new UmbracoDomain(domainModel.DomainName)
320+
{
321+
LanguageId = languageIdByIsoCode[domainModel.IsoCode],
322+
RootContentId = contentId
323+
};
324+
}
320325

321326
assignedDomain.SortOrder = sortOrder++;
322327
newAssignedDomains.Add(assignedDomain);

src/Umbraco.Core/Services/IPublicAccessService.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,23 @@ public interface IPublicAccessService : IService
8585
/// </summary>
8686
/// <param name="key"></param>
8787
/// <returns>Returns null if no entry is found</returns>
88+
/// <remarks>
89+
/// This method supports inheritance by considering ancestor entries (if any),
90+
/// if no entry is found for the specified content key.
91+
/// </remarks>
8892
Task<Attempt<PublicAccessEntry?, PublicAccessOperationStatus>> GetEntryByContentKeyAsync(Guid key);
8993

94+
/// <summary>
95+
/// Gets the entry defined for the content item based on a content key, without taking ancestor entries into account.
96+
/// </summary>
97+
/// <param name="key"></param>
98+
/// <returns>Returns null if no entry is found</returns>
99+
/// <remarks>
100+
/// This method does not support inheritance. Use <see cref="GetEntryByContentKeyAsync"/> to include ancestor entries (if any).
101+
/// </remarks>
102+
Task<Attempt<PublicAccessEntry?, PublicAccessOperationStatus>> GetEntryByContentKeyWithoutAncestorsAsync(Guid key)
103+
=> Task.FromResult(Attempt.SucceedWithStatus<PublicAccessEntry?, PublicAccessOperationStatus>(PublicAccessOperationStatus.EntryNotFound, null));
104+
90105
/// <summary>
91106
/// Deletes the entry and all associated rules for a given key.
92107
/// </summary>

src/Umbraco.Core/Services/PublicAccessService.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System.Globalization;
2+
using Microsoft.Extensions.DependencyInjection;
23
using Microsoft.Extensions.Logging;
4+
using Umbraco.Cms.Core.DependencyInjection;
35
using Umbraco.Cms.Core.Events;
46
using Umbraco.Cms.Core.Models;
57
using Umbraco.Cms.Core.Models.Entities;
@@ -16,19 +18,41 @@ internal class PublicAccessService : RepositoryService, IPublicAccessService
1618
private readonly IPublicAccessRepository _publicAccessRepository;
1719
private readonly IEntityService _entityService;
1820
private readonly IContentService _contentService;
21+
private readonly IIdKeyMap _idKeyMap;
1922

23+
[Obsolete("Please use the constructor that accepts all parameter. Will be removed in V16.")]
2024
public PublicAccessService(
2125
ICoreScopeProvider provider,
2226
ILoggerFactory loggerFactory,
2327
IEventMessagesFactory eventMessagesFactory,
2428
IPublicAccessRepository publicAccessRepository,
2529
IEntityService entityService,
2630
IContentService contentService)
31+
: this(
32+
provider,
33+
loggerFactory,
34+
eventMessagesFactory,
35+
publicAccessRepository,
36+
entityService,
37+
contentService,
38+
StaticServiceProvider.Instance.GetRequiredService<IIdKeyMap>())
39+
{
40+
}
41+
42+
public PublicAccessService(
43+
ICoreScopeProvider provider,
44+
ILoggerFactory loggerFactory,
45+
IEventMessagesFactory eventMessagesFactory,
46+
IPublicAccessRepository publicAccessRepository,
47+
IEntityService entityService,
48+
IContentService contentService,
49+
IIdKeyMap idKeyMap)
2750
: base(provider, loggerFactory, eventMessagesFactory)
2851
{
2952
_publicAccessRepository = publicAccessRepository;
3053
_entityService = entityService;
3154
_contentService = contentService;
55+
_idKeyMap = idKeyMap;
3256
}
3357

3458
/// <summary>
@@ -381,6 +405,23 @@ private Attempt<PublicAccessNodesValidationResult, PublicAccessOperationStatus>
381405
return Task.FromResult(Attempt.SucceedWithStatus<PublicAccessEntry?, PublicAccessOperationStatus>(PublicAccessOperationStatus.Success, entry));
382406
}
383407

408+
public async Task<Attempt<PublicAccessEntry?, PublicAccessOperationStatus>> GetEntryByContentKeyWithoutAncestorsAsync(Guid key)
409+
{
410+
Attempt<PublicAccessEntry?, PublicAccessOperationStatus> result = await GetEntryByContentKeyAsync(key);
411+
if (result.Success is false || result.Result is null)
412+
{
413+
return result;
414+
}
415+
416+
Attempt<Guid> idToKeyAttempt = _idKeyMap.GetKeyForId(result.Result.ProtectedNodeId, UmbracoObjectTypes.Document);
417+
if (idToKeyAttempt.Success is false || idToKeyAttempt.Result != key)
418+
{
419+
return Attempt.SucceedWithStatus<PublicAccessEntry?, PublicAccessOperationStatus>(PublicAccessOperationStatus.EntryNotFound, null);
420+
}
421+
422+
return result;
423+
}
424+
384425
public async Task<Attempt<PublicAccessOperationStatus>> DeleteAsync(Guid key)
385426
{
386427
using (ICoreScope scope = ScopeProvider.CreateCoreScope())

0 commit comments

Comments
 (0)