Content & media url endpoints (#15832)

* First go at the document url controller

Added optimizations for documenturlFactory

* Updated Document Url endpoint

Duplicated the endpoint for media
Cleaned up some code marked async that will never hit a long running operation

* Remove dupplicate attributes

* Rename resource sets to response model

---------

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-04-11 09:10:45 +02:00
committed by GitHub
parent d47638df98
commit 48e9be2b73
13 changed files with 184 additions and 34 deletions

View File

@@ -0,0 +1,35 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Document;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Controllers.Document;
[ApiVersion("1.0")]
public class DocumentUrlController : DocumentControllerBase
{
private readonly IContentService _contentService;
private readonly IDocumentUrlFactory _documentUrlFactory;
public DocumentUrlController(
IContentService contentService,
IDocumentUrlFactory documentUrlFactory)
{
_contentService = contentService;
_documentUrlFactory = documentUrlFactory;
}
[MapToApiVersion("1.0")]
[HttpGet("urls")]
[ProducesResponseType(typeof(IEnumerable<DocumentUrlInfoResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult> GetUrls([FromQuery(Name = "id")] HashSet<Guid> ids)
{
IEnumerable<IContent> items = _contentService.GetByIds(ids);
return Ok(await _documentUrlFactory.CreateUrlSetsAsync(items));
}
}

View File

@@ -52,7 +52,7 @@ public class ByKeyMediaController : MediaControllerBase
return MediaNotFound();
}
MediaResponseModel model = await _mediaPresentationFactory.CreateResponseModelAsync(media);
MediaResponseModel model = _mediaPresentationFactory.CreateResponseModel(media);
return Ok(model);
}
}

View File

@@ -0,0 +1,34 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Media;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Api.Management.Controllers.Media;
[ApiVersion("1.0")]
public class MediaUrlController : MediaControllerBase
{
private readonly IMediaService _mediaService;
private readonly IMediaUrlFactory _mediaUrlFactory;
public MediaUrlController(
IMediaService mediaService,
IMediaUrlFactory mediaUrlFactory)
{
_mediaService = mediaService;
_mediaUrlFactory = mediaUrlFactory;
}
[MapToApiVersion("1.0")]
[HttpGet("urls")]
[ProducesResponseType(typeof(IEnumerable<MediaUrlInfoResponseModel>), StatusCodes.Status200OK)]
public ActionResult GetUrls([FromQuery(Name = "id")] HashSet<Guid> ids)
{
IEnumerable<IMedia> items = _mediaService.GetByIds(ids);
return Ok(_mediaUrlFactory.CreateUrlSets(items));
}
}

View File

@@ -15,6 +15,7 @@ internal static class MediaBuilderExtensions
builder.Services.AddTransient<IMediaPresentationFactory, MediaPresentationFactory>();
builder.Services.AddTransient<IMediaEditingPresentationFactory, MediaEditingPresentationFactory>();
builder.Services.AddTransient<IUrlAssembler, DefaultUrlAssembler>();
builder.Services.AddTransient<IMediaUrlFactory, MediaUrlFactory>();
builder.Services.AddScoped<IAbsoluteUrlBuilder, DefaultAbsoluteUrlBuilder>();
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>().Add<MediaMapDefinition>();

View File

@@ -41,7 +41,7 @@ internal sealed class DocumentPresentationFactory : IDocumentPresentationFactory
{
DocumentResponseModel responseModel = _umbracoMapper.Map<DocumentResponseModel>(content)!;
responseModel.Urls = await _documentUrlFactory.GetUrlsAsync(content);
responseModel.Urls = await _documentUrlFactory.CreateUrlsAsync(content);
Guid? templateKey = content.TemplateId.HasValue
? _templateService.GetAsync(content.TemplateId.Value).Result?.Key

View File

@@ -44,11 +44,11 @@ public class DocumentUrlFactory : IDocumentUrlFactory
_publishedUrlProvider = publishedUrlProvider;
}
public async Task<IEnumerable<DocumentUrlInfo>> GetUrlsAsync(IContent content)
public async Task<IEnumerable<DocumentUrlInfo>> CreateUrlsAsync(IContent content)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
UrlInfo[] urlInfos = (await content.GetContentUrlsAsync(
IEnumerable<UrlInfo> urlInfos = await content.GetContentUrlsAsync(
_publishedRouter,
umbracoContext,
_languageService,
@@ -57,11 +57,24 @@ public class DocumentUrlFactory : IDocumentUrlFactory
_variationContextAccessor,
_loggerFactory.CreateLogger<IContent>(),
_uriUtility,
_publishedUrlProvider)).ToArray();
_publishedUrlProvider);
return urlInfos
.Where(urlInfo => urlInfo.IsUrl)
.Select(urlInfo => new DocumentUrlInfo { Culture = urlInfo.Culture, Url = urlInfo.Text })
.ToArray();
}
public async Task<IEnumerable<DocumentUrlInfoResponseModel>> CreateUrlSetsAsync(IEnumerable<IContent> contentItems)
{
var documentUrlInfoResourceSets = new List<DocumentUrlInfoResponseModel>();
foreach (IContent content in contentItems)
{
IEnumerable<DocumentUrlInfo> urls = await CreateUrlsAsync(content);
documentUrlInfoResourceSets.Add(new DocumentUrlInfoResponseModel(content.Key, urls));
}
return documentUrlInfoResourceSets;
}
}

View File

@@ -5,5 +5,6 @@ namespace Umbraco.Cms.Api.Management.Factories;
public interface IDocumentUrlFactory
{
Task<IEnumerable<DocumentUrlInfo>> GetUrlsAsync(IContent content);
Task<IEnumerable<DocumentUrlInfo>> CreateUrlsAsync(IContent content);
Task<IEnumerable<DocumentUrlInfoResponseModel>> CreateUrlSetsAsync(IEnumerable<IContent> contentItems);
}

View File

@@ -9,7 +9,7 @@ namespace Umbraco.Cms.Api.Management.Factories;
public interface IMediaPresentationFactory
{
Task<MediaResponseModel> CreateResponseModelAsync(IMedia media);
MediaResponseModel CreateResponseModel(IMedia media);
MediaItemResponseModel CreateItemResponseModel(IMediaEntitySlim entity);

View File

@@ -0,0 +1,10 @@
using Umbraco.Cms.Api.Management.ViewModels.Media;
using Umbraco.Cms.Core.Models;
namespace Umbraco.Cms.Api.Management.Factories;
public interface IMediaUrlFactory
{
IEnumerable<MediaUrlInfo> CreateUrls(IMedia media);
IEnumerable<MediaUrlInfoResponseModel> CreateUrlSets(IEnumerable<IMedia> mediaItems);
}

View File

@@ -1,53 +1,33 @@
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Media;
using Umbraco.Cms.Api.Management.ViewModels.Media.Item;
using Umbraco.Cms.Api.Management.ViewModels.MediaType;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Factories;
internal sealed class MediaPresentationFactory : IMediaPresentationFactory
{
private readonly IUmbracoMapper _umbracoMapper;
private readonly ContentSettings _contentSettings;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly IAbsoluteUrlBuilder _absoluteUrlBuilder;
private readonly IMediaUrlFactory _mediaUrlFactory;
public MediaPresentationFactory(
IUmbracoMapper umbracoMapper,
IOptions<ContentSettings> contentSettings,
MediaUrlGeneratorCollection mediaUrlGenerators,
IAbsoluteUrlBuilder absoluteUrlBuilder)
IMediaUrlFactory mediaUrlFactory)
{
_umbracoMapper = umbracoMapper;
_contentSettings = contentSettings.Value;
_mediaUrlGenerators = mediaUrlGenerators;
_absoluteUrlBuilder = absoluteUrlBuilder;
_mediaUrlFactory = mediaUrlFactory;
}
public Task<MediaResponseModel> CreateResponseModelAsync(IMedia media)
public MediaResponseModel CreateResponseModel(IMedia media)
{
MediaResponseModel responseModel = _umbracoMapper.Map<MediaResponseModel>(media)!;
responseModel.Urls = media
.GetUrls(_contentSettings, _mediaUrlGenerators)
.WhereNotNull()
.Select(mediaUrl => new MediaUrlInfo
{
Culture = null,
Url = _absoluteUrlBuilder.ToAbsoluteUrl(mediaUrl).ToString(),
})
.ToArray();
responseModel.Urls = _mediaUrlFactory.CreateUrls(media);
return Task.FromResult(responseModel);
return responseModel;
}
public MediaItemResponseModel CreateItemResponseModel(IMediaEntitySlim entity)

View File

@@ -0,0 +1,48 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.Routing;
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Document;
using Umbraco.Cms.Api.Management.ViewModels.Media;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Factories;
public class MediaUrlFactory : IMediaUrlFactory
{
private readonly ContentSettings _contentSettings;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly IAbsoluteUrlBuilder _absoluteUrlBuilder;
public MediaUrlFactory(
IOptions<ContentSettings> contentSettings,
MediaUrlGeneratorCollection mediaUrlGenerators,
IAbsoluteUrlBuilder absoluteUrlBuilder)
{
_contentSettings = contentSettings.Value;
_mediaUrlGenerators = mediaUrlGenerators;
_absoluteUrlBuilder = absoluteUrlBuilder;
}
public IEnumerable<MediaUrlInfo> CreateUrls(IMedia media) =>
media
.GetUrls(_contentSettings, _mediaUrlGenerators)
.WhereNotNull()
.Select(mediaUrl => new MediaUrlInfo
{
Culture = null,
Url = _absoluteUrlBuilder.ToAbsoluteUrl(mediaUrl).ToString(),
})
.ToArray();
public IEnumerable<MediaUrlInfoResponseModel> CreateUrlSets(IEnumerable<IMedia> mediaItems) =>
mediaItems.Select(media => new MediaUrlInfoResponseModel(media.Key, CreateUrls(media))).ToArray();
}

View File

@@ -0,0 +1,14 @@
namespace Umbraco.Cms.Api.Management.ViewModels.Document;
public sealed class DocumentUrlInfoResponseModel
{
public DocumentUrlInfoResponseModel(Guid id, IEnumerable<DocumentUrlInfo> urlInfos)
{
Id = id;
UrlInfos = urlInfos;
}
public Guid Id { get; }
public IEnumerable<DocumentUrlInfo> UrlInfos { get; }
}

View File

@@ -0,0 +1,14 @@
namespace Umbraco.Cms.Api.Management.ViewModels.Media;
public sealed class MediaUrlInfoResponseModel
{
public MediaUrlInfoResponseModel(Guid id, IEnumerable<MediaUrlInfo> urlInfos)
{
Id = id;
UrlInfos = urlInfos;
}
public Guid Id { get; }
public IEnumerable<MediaUrlInfo> UrlInfos { get; }
}