[v14] Absolute media urls (#15503)

* Made a replaceble solution to support absolute urls for media/user avatars in the management API

* PR suggestion

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* PR suggestion

Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>

* PR suggestion/fix and added missing switch case

---------

Co-authored-by: Sven Geusens <sge@umbraco.dk>
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
This commit is contained in:
Sven Geusens
2024-01-10 10:01:06 +01:00
committed by GitHub
parent a6ccd5a7a9
commit 33f2b26bf6
8 changed files with 116 additions and 44 deletions

View File

@@ -1,8 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.Mapping.Media;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Routing;
namespace Umbraco.Cms.Api.Management.DependencyInjection;
@@ -12,6 +14,8 @@ internal static class MediaBuilderExtensions
{
builder.Services.AddTransient<IMediaPresentationModelFactory, MediaPresentationModelFactory>();
builder.Services.AddTransient<IMediaEditingPresentationFactory, MediaEditingPresentationFactory>();
builder.Services.AddTransient<IUrlAssembler, DefaultUrlAssembler>();
builder.Services.AddScoped<IAbsoluteUrlBuilder, DefaultAbsoluteUrlBuilder>();
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>().Add<MediaMapDefinition>();

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Media;
using Umbraco.Cms.Core.Configuration.Models;
@@ -14,12 +15,18 @@ public class MediaPresentationModelFactory : IMediaPresentationModelFactory
private readonly IUmbracoMapper _umbracoMapper;
private readonly ContentSettings _contentSettings;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly IAbsoluteUrlBuilder _absoluteUrlBuilder;
public MediaPresentationModelFactory(IUmbracoMapper umbracoMapper, IOptions<ContentSettings> contentSettings, MediaUrlGeneratorCollection mediaUrlGenerators)
public MediaPresentationModelFactory(
IUmbracoMapper umbracoMapper,
IOptions<ContentSettings> contentSettings,
MediaUrlGeneratorCollection mediaUrlGenerators,
IAbsoluteUrlBuilder absoluteUrlBuilder)
{
_umbracoMapper = umbracoMapper;
_contentSettings = contentSettings.Value;
_mediaUrlGenerators = mediaUrlGenerators;
_absoluteUrlBuilder = absoluteUrlBuilder;
}
public Task<MediaResponseModel> CreateResponseModelAsync(IMedia media)
@@ -32,7 +39,7 @@ public class MediaPresentationModelFactory : IMediaPresentationModelFactory
.Select(mediaUrl => new ContentUrlInfo
{
Culture = null,
Url = mediaUrl
Url = _absoluteUrlBuilder.ToAbsoluteUrl(mediaUrl).ToString(),
})
.ToArray();

View File

@@ -1,4 +1,5 @@
using Umbraco.Cms.Api.Management.ViewModels.User;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Api.Management.ViewModels.User;
using Umbraco.Cms.Api.Management.ViewModels.User.Current;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
@@ -17,19 +18,22 @@ public class UserPresentationFactory : IUserPresentationFactory
private readonly MediaFileManager _mediaFileManager;
private readonly IImageUrlGenerator _imageUrlGenerator;
private readonly IUserGroupPresentationFactory _userGroupPresentationFactory;
private readonly IAbsoluteUrlBuilder _absoluteUrlBuilder;
public UserPresentationFactory(
IEntityService entityService,
AppCaches appCaches,
MediaFileManager mediaFileManager,
IImageUrlGenerator imageUrlGenerator,
IUserGroupPresentationFactory userGroupPresentationFactory)
IUserGroupPresentationFactory userGroupPresentationFactory,
IAbsoluteUrlBuilder absoluteUrlBuilder)
{
_entityService = entityService;
_appCaches = appCaches;
_mediaFileManager = mediaFileManager;
_imageUrlGenerator = imageUrlGenerator;
_userGroupPresentationFactory = userGroupPresentationFactory;
_absoluteUrlBuilder = absoluteUrlBuilder;
}
public UserResponseModel CreateResponseModel(IUser user)
@@ -39,7 +43,8 @@ public class UserPresentationFactory : IUserPresentationFactory
Id = user.Key,
Email = user.Email,
Name = user.Name ?? string.Empty,
AvatarUrls = user.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator),
AvatarUrls = user.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator)
.Select(url => _absoluteUrlBuilder.ToAbsoluteUrl(url).ToString()),
UserName = user.Username,
LanguageIsoCode = user.Language,
CreateDate = user.CreateDate,

View File

@@ -0,0 +1,26 @@
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Web;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Routing;
public class DefaultAbsoluteUrlBuilder : IAbsoluteUrlBuilder
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IUrlAssembler _urlAssembler;
public DefaultAbsoluteUrlBuilder(IUmbracoContextAccessor umbracoContextAccessor, IUrlAssembler urlAssembler)
{
_umbracoContextAccessor = umbracoContextAccessor;
_urlAssembler = urlAssembler;
}
public Uri ToAbsoluteUrl(string url)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
Uri current = umbracoContext.CleanedUmbracoUrl;
return _urlAssembler.AssembleUrl(url, current, UrlMode.Absolute);
}
}

View File

@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.Routing;
public interface IAbsoluteUrlBuilder
{
Uri ToAbsoluteUrl(string url);
}

View File

@@ -1,4 +1,6 @@
using Umbraco.Cms.Core.Models.PublishedContent;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
namespace Umbraco.Cms.Core.Routing;
@@ -10,11 +12,19 @@ public class DefaultMediaUrlProvider : IMediaUrlProvider
{
private readonly MediaUrlGeneratorCollection _mediaPathGenerators;
private readonly UriUtility _uriUtility;
private readonly IUrlAssembler _urlAssembler;
public DefaultMediaUrlProvider(MediaUrlGeneratorCollection mediaPathGenerators, UriUtility uriUtility)
public DefaultMediaUrlProvider(MediaUrlGeneratorCollection mediaPathGenerators, UriUtility uriUtility, IUrlAssembler urlAssembler)
{
_mediaPathGenerators = mediaPathGenerators ?? throw new ArgumentNullException(nameof(mediaPathGenerators));
_uriUtility = uriUtility;
_urlAssembler = urlAssembler;
}
[Obsolete("Use the constructor that has the IUrlAssembler instead. Scheduled to be removed in v15")]
public DefaultMediaUrlProvider(MediaUrlGeneratorCollection mediaPathGenerators, UriUtility uriUtility)
: this(mediaPathGenerators, uriUtility, StaticServiceProvider.Instance.GetRequiredService<IUrlAssembler>())
{
}
/// <inheritdoc />
@@ -38,46 +48,10 @@ public class DefaultMediaUrlProvider : IMediaUrlProvider
if (_mediaPathGenerators.TryGetMediaPath(propType?.EditorAlias, value, out var path))
{
Uri url = AssembleUrl(path!, current, mode);
Uri url = _urlAssembler.AssembleUrl(path!, current, mode);
return UrlInfo.Url(url.ToString(), culture);
}
return null;
}
private Uri AssembleUrl(string path, Uri current, UrlMode mode)
{
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentException($"{nameof(path)} cannot be null or whitespace", nameof(path));
}
// the stored path is absolute so we just return it as is
if (Uri.IsWellFormedUriString(path, UriKind.Absolute))
{
return new Uri(path);
}
Uri uri;
if (current == null)
{
mode = UrlMode.Relative; // best we can do
}
switch (mode)
{
case UrlMode.Absolute:
uri = new Uri(current?.GetLeftPart(UriPartial.Authority) + path);
break;
case UrlMode.Relative:
case UrlMode.Auto:
uri = new Uri(path, UriKind.Relative);
break;
default:
throw new ArgumentOutOfRangeException(nameof(mode));
}
return _uriUtility.MediaUriFromUmbraco(uri);
}
}

View File

@@ -0,0 +1,42 @@
using Umbraco.Cms.Core.Models.PublishedContent;
namespace Umbraco.Cms.Core.Routing;
public class DefaultUrlAssembler : IUrlAssembler
{
private readonly UriUtility _uriUtility;
public DefaultUrlAssembler(UriUtility uriUtility) => _uriUtility = uriUtility;
public Uri AssembleUrl(string path, Uri current, UrlMode mode)
{
if (string.IsNullOrWhiteSpace(path))
{
throw new ArgumentException($"{nameof(path)} cannot be null or whitespace", nameof(path));
}
// the path is absolute so we just return it as is
if (Uri.IsWellFormedUriString(path, UriKind.Absolute))
{
return new Uri(path);
}
Uri uri;
switch (mode)
{
case UrlMode.Absolute:
uri = new Uri(current.GetLeftPart(UriPartial.Authority) + path);
break;
case UrlMode.Relative:
case UrlMode.Auto:
case UrlMode.Default:
uri = new Uri(path, UriKind.Relative);
break;
default:
throw new ArgumentOutOfRangeException(nameof(mode));
}
return _uriUtility.MediaUriFromUmbraco(uri);
}
}

View File

@@ -0,0 +1,8 @@
using Umbraco.Cms.Core.Models.PublishedContent;
namespace Umbraco.Cms.Core.Routing;
public interface IUrlAssembler
{
Uri AssembleUrl(string path, Uri current, UrlMode mode);
}