diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/MediaBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/MediaBuilderExtensions.cs index c2ebda5895..e800031dbf 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/MediaBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/MediaBuilderExtensions.cs @@ -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(); builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddScoped(); builder.WithCollectionBuilder().Add(); diff --git a/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs index cf3fd09993..0b8e077ffc 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/MediaPresentationModelFactory.cs @@ -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, MediaUrlGeneratorCollection mediaUrlGenerators) + public MediaPresentationModelFactory( + IUmbracoMapper umbracoMapper, + IOptions contentSettings, + MediaUrlGeneratorCollection mediaUrlGenerators, + IAbsoluteUrlBuilder absoluteUrlBuilder) { _umbracoMapper = umbracoMapper; _contentSettings = contentSettings.Value; _mediaUrlGenerators = mediaUrlGenerators; + _absoluteUrlBuilder = absoluteUrlBuilder; } public Task 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(); diff --git a/src/Umbraco.Cms.Api.Management/Factories/UserPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/UserPresentationFactory.cs index aaad2677ef..0593628e1c 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/UserPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/UserPresentationFactory.cs @@ -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, diff --git a/src/Umbraco.Cms.Api.Management/Routing/DefaultAbsoluteUrlBuilder.cs b/src/Umbraco.Cms.Api.Management/Routing/DefaultAbsoluteUrlBuilder.cs new file mode 100644 index 0000000000..2126e5f77c --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Routing/DefaultAbsoluteUrlBuilder.cs @@ -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); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Routing/IAbsoluteUrlBuilder.cs b/src/Umbraco.Cms.Api.Management/Routing/IAbsoluteUrlBuilder.cs new file mode 100644 index 0000000000..57a99e8e28 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Routing/IAbsoluteUrlBuilder.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.Routing; + +public interface IAbsoluteUrlBuilder +{ + Uri ToAbsoluteUrl(string url); +} diff --git a/src/Umbraco.Core/Routing/DefaultMediaUrlProvider.cs b/src/Umbraco.Core/Routing/DefaultMediaUrlProvider.cs index d1c79783f0..b9824731bf 100644 --- a/src/Umbraco.Core/Routing/DefaultMediaUrlProvider.cs +++ b/src/Umbraco.Core/Routing/DefaultMediaUrlProvider.cs @@ -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()) + { } /// @@ -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); - } } diff --git a/src/Umbraco.Core/Routing/DefaultUrlAssembler.cs b/src/Umbraco.Core/Routing/DefaultUrlAssembler.cs new file mode 100644 index 0000000000..25c1ce3e32 --- /dev/null +++ b/src/Umbraco.Core/Routing/DefaultUrlAssembler.cs @@ -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); + } +} diff --git a/src/Umbraco.Core/Routing/IUrlAssembler.cs b/src/Umbraco.Core/Routing/IUrlAssembler.cs new file mode 100644 index 0000000000..c56b216e70 --- /dev/null +++ b/src/Umbraco.Core/Routing/IUrlAssembler.cs @@ -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); +}