Skip to content

Commit 37c0990

Browse files
committed
Change preview URL generation to happen at preview time based on provider alias
1 parent 64ae0ab commit 37c0990

18 files changed

+259
-137
lines changed

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Asp.Versioning;
22
using Microsoft.AspNetCore.Http;
33
using Microsoft.AspNetCore.Mvc;
4+
using Umbraco.Cms.Api.Common.Builders;
45
using Umbraco.Cms.Api.Management.Factories;
56
using Umbraco.Cms.Api.Management.ViewModels.Document;
67
using Umbraco.Cms.Core.Models;
@@ -23,12 +24,30 @@ public DocumentPreviewUrlController(
2324
}
2425

2526
[MapToApiVersion("1.0")]
26-
[HttpGet("preview-urls")]
27-
[ProducesResponseType(typeof(IEnumerable<DocumentUrlInfoResponseModel>), StatusCodes.Status200OK)]
28-
public async Task<IActionResult> GetPreviewUrls([FromQuery(Name = "id")] HashSet<Guid> ids)
27+
[HttpGet("{id:guid}/preview-url")]
28+
[ProducesResponseType(typeof(DocumentUrlInfo), StatusCodes.Status200OK)]
29+
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
30+
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
31+
public async Task<IActionResult> GetPreviewUrl(Guid id, string providerAlias, string? culture, string? segment)
2932
{
30-
IEnumerable<IContent> items = _contentService.GetByIds(ids);
33+
IContent? content = _contentService.GetById(id);
34+
if (content is null)
35+
{
36+
return NotFound(new ProblemDetailsBuilder()
37+
.WithTitle("Document not found")
38+
.WithDetail("The requested document did not exist.")
39+
.Build());
40+
}
3141

32-
return Ok(await _documentUrlFactory.CreatePreviewUrlSetsAsync(items));
42+
DocumentUrlInfo? previewUrlInfo = await _documentUrlFactory.GetPreviewUrlAsync(content, providerAlias, culture, segment);
43+
if (previewUrlInfo is null)
44+
{
45+
return BadRequest(new ProblemDetailsBuilder()
46+
.WithTitle("No preview URL for document")
47+
.WithDetail("Failed to produce a preview URL for the requested document.")
48+
.Build());
49+
}
50+
51+
return Ok(previewUrlInfo);
3352
}
3453
}

src/Umbraco.Cms.Api.Management/Controllers/Preview/EnterPreviewController.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Umbraco.Cms.Api.Management.Controllers.Preview;
88

99
[ApiVersion("1.0")]
10+
[Obsolete("Do not use this. Preview state is initiated implicitly by the preview URL generation. Scheduled for removal in V18.")]
1011
public class EnterPreviewController : PreviewControllerBase
1112
{
1213
private readonly IPreviewService _previewService;
Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,46 @@
1+
using Microsoft.Extensions.Logging;
2+
using Umbraco.Cms.Api.Management.Routing;
13
using Umbraco.Cms.Api.Management.ViewModels.Document;
24
using Umbraco.Cms.Core.Models;
5+
using Umbraco.Cms.Core.Models.Membership;
36
using Umbraco.Cms.Core.Routing;
7+
using Umbraco.Cms.Core.Security;
8+
using Umbraco.Cms.Core.Services;
9+
using Umbraco.Extensions;
410

511
namespace Umbraco.Cms.Api.Management.Factories;
612

713
public class DocumentUrlFactory : IDocumentUrlFactory
814
{
915
private readonly IPublishedUrlInfoProvider _publishedUrlInfoProvider;
1016
private readonly UrlProviderCollection _urlProviders;
17+
private readonly IPreviewService _previewService;
18+
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
19+
private readonly IAbsoluteUrlBuilder _absoluteUrlBuilder;
20+
private readonly ILogger<DocumentUrlFactory> _logger;
1121

12-
public DocumentUrlFactory(IPublishedUrlInfoProvider publishedUrlInfoProvider, UrlProviderCollection urlProviders)
22+
public DocumentUrlFactory(
23+
IPublishedUrlInfoProvider publishedUrlInfoProvider,
24+
UrlProviderCollection urlProviders,
25+
IPreviewService previewService,
26+
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
27+
IAbsoluteUrlBuilder absoluteUrlBuilder,
28+
ILogger<DocumentUrlFactory> logger)
1329
{
1430
_publishedUrlInfoProvider = publishedUrlInfoProvider;
1531
_urlProviders = urlProviders;
32+
_previewService = previewService;
33+
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
34+
_absoluteUrlBuilder = absoluteUrlBuilder;
35+
_logger = logger;
1636
}
1737

1838
public async Task<IEnumerable<DocumentUrlInfo>> CreateUrlsAsync(IContent content)
1939
{
2040
ISet<UrlInfo> urlInfos = await _publishedUrlInfoProvider.GetAllAsync(content);
21-
return CreateDocumentUrlInfos(urlInfos);
41+
return urlInfos
42+
.Select(urlInfo => CreateDocumentUrlInfo(urlInfo, false))
43+
.ToArray();
2244
}
2345

2446
public async Task<IEnumerable<DocumentUrlInfoResponseModel>> CreateUrlSetsAsync(IEnumerable<IContent> contentItems)
@@ -34,28 +56,53 @@ public async Task<IEnumerable<DocumentUrlInfoResponseModel>> CreateUrlSetsAsync(
3456
return documentUrlInfoResourceSets;
3557
}
3658

37-
public Task<IEnumerable<DocumentUrlInfoResponseModel>> CreatePreviewUrlSetsAsync(IEnumerable<IContent> contentItems)
59+
public async Task<DocumentUrlInfo?> GetPreviewUrlAsync(IContent content, string providerAlias, string? culture, string? segment)
3860
{
39-
DocumentUrlInfoResponseModel[] documentUrlInfoResourceSets = contentItems.Select(content =>
61+
IUrlProvider? provider = _urlProviders.FirstOrDefault(provider => provider.Alias.InvariantEquals(providerAlias));
62+
if (provider is null)
63+
{
64+
_logger.LogError("Could not resolve the URL provider requested for preview: {providerAlias}", providerAlias);
65+
return null;
66+
}
67+
68+
UrlInfo? previewUrlInfo = await provider.GetPreviewUrlAsync(content, culture, segment);
69+
if (previewUrlInfo is null)
70+
{
71+
_logger.LogError("The URL provider: {providerAlias} could not generate a preview URL for content with key: {contentKey}", providerAlias, content.Key);
72+
return null;
73+
}
74+
75+
// must initiate preview state for internal preview URLs
76+
if (previewUrlInfo.Url is not null && previewUrlInfo.IsExternal is false)
77+
{
78+
IUser? currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser;
79+
if (currentUser is null)
4080
{
41-
IEnumerable<UrlInfo> previewUrls = _urlProviders.SelectMany(provider => provider.GetPreviewUrls(content));
42-
return new DocumentUrlInfoResponseModel(content.Key, CreateDocumentUrlInfos(previewUrls));
43-
})
44-
.ToArray();
81+
_logger.LogError("Could not access the current backoffice user while attempting to authenticate for preview.");
82+
return null;
83+
}
4584

46-
return Task.FromResult<IEnumerable<DocumentUrlInfoResponseModel>>(documentUrlInfoResourceSets);
85+
if (await _previewService.TryEnterPreviewAsync(currentUser) is false)
86+
{
87+
_logger.LogError("A server error occured, could not initiate an authenticated preview state for the current user.");
88+
return null;
89+
}
90+
}
91+
92+
return CreateDocumentUrlInfo(previewUrlInfo, previewUrlInfo.IsExternal is false);
4793
}
4894

49-
private IEnumerable<DocumentUrlInfo> CreateDocumentUrlInfos(IEnumerable<UrlInfo> urlInfos)
50-
=> urlInfos
51-
.Where(urlInfo => urlInfo.Url is not null)
52-
.Select(urlInfo => new DocumentUrlInfo
53-
{
54-
Culture = urlInfo.Culture,
55-
Url = urlInfo.Url!.ToString(),
56-
Message = urlInfo.Message,
57-
IsExternal = urlInfo.IsExternal,
58-
Provider = urlInfo.Provider,
59-
})
60-
.ToArray();
95+
private DocumentUrlInfo CreateDocumentUrlInfo(UrlInfo urlInfo, bool ensureAbsoluteUrl)
96+
{
97+
var url = urlInfo.Url?.ToString();
98+
return new DocumentUrlInfo
99+
{
100+
Culture = urlInfo.Culture,
101+
Url = ensureAbsoluteUrl && url is not null
102+
? _absoluteUrlBuilder.ToAbsoluteUrl(url).ToString()
103+
: url,
104+
Message = urlInfo.Message,
105+
Provider = urlInfo.Provider,
106+
};
107+
}
61108
}

src/Umbraco.Cms.Api.Management/Factories/IDocumentUrlFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ public interface IDocumentUrlFactory
99

1010
Task<IEnumerable<DocumentUrlInfoResponseModel>> CreateUrlSetsAsync(IEnumerable<IContent> contentItems);
1111

12-
Task<IEnumerable<DocumentUrlInfoResponseModel>> CreatePreviewUrlSetsAsync(IEnumerable<IContent> contentItems);
12+
Task<DocumentUrlInfo?> GetPreviewUrlAsync(IContent content, string providerAlias, string? culture, string? segment);
1313
}

src/Umbraco.Cms.Api.Management/Factories/MediaUrlFactory.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public IEnumerable<MediaUrlInfo> CreateUrls(IMedia media) =>
4040
{
4141
Culture = null,
4242
Url = _absoluteUrlBuilder.ToAbsoluteUrl(mediaUrl).ToString(),
43-
IsExternal = false,
4443
})
4544
.ToArray();
4645

src/Umbraco.Cms.Api.Management/Factories/ReziseImageUrlFactory.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ private IEnumerable<MediaUrlInfo> CreateThumbnailUrls(IEnumerable<string> urls,
5353
{
5454
Culture = null,
5555
Url = _absoluteUrlBuilder.ToAbsoluteUrl(url).ToString(),
56-
IsExternal = false,
5756
};
5857
}
5958

@@ -77,7 +76,6 @@ private IEnumerable<MediaUrlInfo> CreateThumbnailUrls(IEnumerable<string> urls,
7776
{
7877
Culture = null,
7978
Url = _absoluteUrlBuilder.ToAbsoluteUrl(relativeUrl).ToString(),
80-
IsExternal = false,
8179
};
8280
}
8381
}

0 commit comments

Comments
 (0)