Add endpoint for retrieving "folder" media types. (#16345)
* Add endpoint for retrieving "folder" media types. * The system Folder media type should always be considered a "folder"
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.MediaType.Item;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.ContentTypeEditing;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.MediaType.Item;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class FolderMediaTypeItemController : MediaTypeItemControllerBase
|
||||
{
|
||||
private readonly IMediaTypeEditingService _mediaTypeEditingService;
|
||||
private readonly IUmbracoMapper _mapper;
|
||||
|
||||
public FolderMediaTypeItemController(IMediaTypeEditingService mediaTypeEditingService, IUmbracoMapper mapper)
|
||||
{
|
||||
_mediaTypeEditingService = mediaTypeEditingService;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpGet("folders")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedModel<MediaTypeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> Folders(CancellationToken cancellationToken, int skip = 0, int take = 100)
|
||||
{
|
||||
PagedModel<IMediaType> mediaTypes = await _mediaTypeEditingService.GetFolderMediaTypes(skip, take);
|
||||
|
||||
var result = new PagedModel<MediaTypeItemResponseModel>
|
||||
{
|
||||
Items = _mapper.MapEnumerable<IMediaType, MediaTypeItemResponseModel>(mediaTypes.Items),
|
||||
Total = mediaTypes.Total
|
||||
};
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
@@ -13217,6 +13217,61 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/item/media-type/folders": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Media Type"
|
||||
],
|
||||
"operationId": "GetItemMediaTypeFolders",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PagedModelMediaTypeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
},
|
||||
"403": {
|
||||
"description": "The authenticated user do not have access to this resource"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/item/media-type/search": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -45027,4 +45082,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,4 +16,6 @@ public interface IMediaTypeEditingService
|
||||
IEnumerable<string> currentPropertyAliases);
|
||||
|
||||
Task<PagedModel<IMediaType>> GetMediaTypesForFileExtensionAsync(string fileExtension, int skip, int take);
|
||||
|
||||
Task<PagedModel<IMediaType>> GetFolderMediaTypes(int skip, int take);
|
||||
}
|
||||
|
||||
@@ -102,6 +102,35 @@ internal sealed class MediaTypeEditingService : ContentTypeEditingServiceBase<IM
|
||||
|
||||
}
|
||||
|
||||
public Task<PagedModel<IMediaType>> GetFolderMediaTypes(int skip, int take)
|
||||
{
|
||||
// we'll consider it a "folder" media type if it:
|
||||
// - does not contain an umbracoFile property
|
||||
// - has any allowed types below itself
|
||||
var folderMediaTypes = _mediaTypeService
|
||||
.GetAll()
|
||||
.Where(mt =>
|
||||
mt.CompositionPropertyTypes.Any(pt => pt.Alias == Constants.Conventions.Media.File) is false
|
||||
&& mt.AllowedContentTypes?.Any() is true)
|
||||
.ToList();
|
||||
|
||||
// as a special case, the "Folder" system media type must always be included
|
||||
if (folderMediaTypes.Any(mediaType => mediaType.Alias == Constants.Conventions.MediaTypes.Folder) is false)
|
||||
{
|
||||
IMediaType? defaultFolderMediaType = _mediaTypeService.Get(Constants.Conventions.MediaTypes.Folder);
|
||||
if (defaultFolderMediaType is not null)
|
||||
{
|
||||
folderMediaTypes.Add(defaultFolderMediaType);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(new PagedModel<IMediaType>
|
||||
{
|
||||
Items = folderMediaTypes.Skip(skip).Take(take),
|
||||
Total = folderMediaTypes.Count
|
||||
});
|
||||
}
|
||||
|
||||
protected override IMediaType CreateContentType(IShortStringHelper shortStringHelper, int parentId)
|
||||
=> new MediaType(shortStringHelper, parentId);
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaTypeEditingServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Get_Default_Folder_Media_Type()
|
||||
{
|
||||
var folderMediaTypes = await MediaTypeEditingService.GetFolderMediaTypes( 0, 100);
|
||||
Assert.AreEqual(1, folderMediaTypes.Total);
|
||||
Assert.AreEqual(Constants.Conventions.MediaTypes.Folder, folderMediaTypes.Items.First().Alias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Yield_Multiple_Folder_Media_Types()
|
||||
{
|
||||
var imageMediaType = MediaTypeService.Get(Constants.Conventions.MediaTypes.Image);
|
||||
|
||||
var createModel = MediaTypeCreateModel("Test Media Type", "testMediaType");
|
||||
createModel.Description = "This is the Test description";
|
||||
createModel.Icon = "icon icon-something";
|
||||
createModel.AllowedAsRoot = true;
|
||||
createModel.Properties = [];
|
||||
createModel.AllowedContentTypes = new[]
|
||||
{
|
||||
new ContentTypeSort { Alias = imageMediaType.Alias, Key = imageMediaType.Key }
|
||||
};
|
||||
|
||||
await MediaTypeEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
|
||||
|
||||
var folderMediaTypes = await MediaTypeEditingService.GetFolderMediaTypes( 0, 100);
|
||||
Assert.AreEqual(2, folderMediaTypes.Total);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
var aliases = folderMediaTypes.Items.Select(i => i.Alias).ToArray();
|
||||
Assert.IsTrue(aliases.Contains(Constants.Conventions.MediaTypes.Folder));
|
||||
Assert.IsTrue(aliases.Contains("testMediaType"));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task System_Folder_Media_Type_Is_Always_Included()
|
||||
{
|
||||
// update the system "Folder" media type so it does not pass the conventions for a "folder" media type
|
||||
// - remove all allowed child content types
|
||||
// - add an "umbracoFile" property
|
||||
var systemFolderMediaType = MediaTypeService.Get(Constants.Conventions.MediaTypes.Folder)!;
|
||||
var updateModel = MediaTypeUpdateModel(Constants.Conventions.MediaTypes.Folder, Constants.Conventions.MediaTypes.Folder);
|
||||
updateModel.Properties = new[]
|
||||
{
|
||||
MediaTypePropertyTypeModel("Test Property", Constants.Conventions.Media.File)
|
||||
};
|
||||
updateModel.AllowedContentTypes = [];
|
||||
|
||||
var updateResult = await MediaTypeEditingService.UpdateAsync(systemFolderMediaType, updateModel, Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(updateResult.Success);
|
||||
|
||||
// despite the system "Folder" media type no longer living up to the "folder" media type requirements,
|
||||
// it should still be considered a "folder"
|
||||
var folderMediaTypes = await MediaTypeEditingService.GetFolderMediaTypes( 0, 100);
|
||||
Assert.AreEqual(1, folderMediaTypes.Total);
|
||||
Assert.AreEqual(Constants.Conventions.MediaTypes.Folder, folderMediaTypes.Items.First().Alias);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Folder_Media_Types_Must_Have_Allowed_Content_Types()
|
||||
{
|
||||
var createModel = MediaTypeCreateModel("Test Media Type", "testMediaType");
|
||||
createModel.Description = "This is the Test description";
|
||||
createModel.Icon = "icon icon-something";
|
||||
createModel.AllowedAsRoot = true;
|
||||
createModel.Properties = [];
|
||||
createModel.AllowedContentTypes = [];
|
||||
|
||||
await MediaTypeEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
|
||||
|
||||
var folderMediaTypes = await MediaTypeEditingService.GetFolderMediaTypes( 0, 100);
|
||||
Assert.AreEqual(1, folderMediaTypes.Total);
|
||||
Assert.AreEqual(Constants.Conventions.MediaTypes.Folder, folderMediaTypes.Items.First().Alias);
|
||||
}
|
||||
}
|
||||
@@ -148,6 +148,12 @@
|
||||
<Compile Update="Umbraco.Infrastructure\Services\ContentBlueprintEditingServiceTests.Update.cs">
|
||||
<DependentUpon>ContentBlueprintEditingServiceTests.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Umbraco.Core\Services\MediaTypeEditingServiceTests.GetMediaTypesForFileExtension.cs">
|
||||
<DependentUpon>MediaTypeEditingServiceTests.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Umbraco.Core\Services\MediaTypeEditingServiceTests.GetFolderMediaTypes.cs">
|
||||
<DependentUpon>MediaTypeEditingServiceTests.cs</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user