CRUD API for media + get-by-id for media type (#13934)
* CRUD API for media + get by ID for media types * A little housekeeping for documents (align with media) * Update Open API json * Add messages to NotFound results (both content and media) * Review changes; use same model for content and media URLs + return bad request when trying to move something to trash that is already in trash * Fix bad merge + rename base (response) classes appropriately between both media and content types
This commit is contained in:
@@ -32,6 +32,10 @@ public class ContentControllerBase : ManagementApiControllerBase
|
||||
.WithDetail("The selected template was not allowed for the operation.")
|
||||
.Build()),
|
||||
ContentEditingOperationStatus.PropertyTypeNotFound => NotFound("One or more property types could not be found"),
|
||||
ContentEditingOperationStatus.InTrash => BadRequest(new ProblemDetailsBuilder()
|
||||
.WithTitle("Content is in the recycle bin")
|
||||
.WithDetail("Could not perform the operation because the targeted content was in the recycle bin.")
|
||||
.Build()),
|
||||
ContentEditingOperationStatus.Unknown => StatusCode(StatusCodes.Status500InternalServerError, "Unknown error. Please see the log for more details."),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown content operation status.")
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ByKeyDocumentController : DocumentControllerBase
|
||||
IContent? content = await _contentEditingService.GetAsync(key);
|
||||
if (content == null)
|
||||
{
|
||||
return NotFound();
|
||||
return DocumentNotFound();
|
||||
}
|
||||
|
||||
DocumentResponseModel model = await _documentPresentationFactory.CreateResponseModelAsync(content);
|
||||
|
||||
@@ -11,4 +11,5 @@ namespace Umbraco.Cms.Api.Management.Controllers.Document;
|
||||
[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Document))]
|
||||
public abstract class DocumentControllerBase : ContentControllerBase
|
||||
{
|
||||
protected IActionResult DocumentNotFound() => NotFound("The requested Document could not be found");
|
||||
}
|
||||
|
||||
@@ -13,18 +13,15 @@ namespace Umbraco.Cms.Api.Management.Controllers.Document;
|
||||
|
||||
public class UpdateDocumentController : DocumentControllerBase
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IContentEditingService _contentEditingService;
|
||||
private readonly IDocumentEditingPresentationFactory _documentEditingPresentationFactory;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public UpdateDocumentController(
|
||||
IContentService contentService,
|
||||
IContentEditingService contentEditingService,
|
||||
IDocumentEditingPresentationFactory documentEditingPresentationFactory,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_contentService = contentService;
|
||||
_contentEditingService = contentEditingService;
|
||||
_documentEditingPresentationFactory = documentEditingPresentationFactory;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
@@ -37,10 +34,10 @@ public class UpdateDocumentController : DocumentControllerBase
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Update(Guid key, UpdateDocumentRequestModel requestModel)
|
||||
{
|
||||
IContent? content = _contentService.GetById(key);
|
||||
IContent? content = await _contentEditingService.GetAsync(key);
|
||||
if (content == null)
|
||||
{
|
||||
return NotFound();
|
||||
return DocumentNotFound();
|
||||
}
|
||||
|
||||
ContentUpdateModel model = _documentEditingPresentationFactory.MapUpdateModel(requestModel);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media;
|
||||
|
||||
public class ByKeyMediaController : MediaControllerBase
|
||||
{
|
||||
private readonly IMediaEditingService _mediaEditingService;
|
||||
private readonly IMediaPresentationModelFactory _mediaPresentationModelFactory;
|
||||
|
||||
public ByKeyMediaController(IMediaEditingService mediaEditingService, IMediaPresentationModelFactory mediaPresentationModelFactory)
|
||||
{
|
||||
_mediaEditingService = mediaEditingService;
|
||||
_mediaPresentationModelFactory = mediaPresentationModelFactory;
|
||||
}
|
||||
|
||||
[HttpGet("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(DocumentResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ByKey(Guid key)
|
||||
{
|
||||
IMedia? media = await _mediaEditingService.GetAsync(key);
|
||||
if (media == null)
|
||||
{
|
||||
return MediaNotFound();
|
||||
}
|
||||
|
||||
MediaResponseModel model = await _mediaPresentationModelFactory.CreateResponseModelAsync(media);
|
||||
return Ok(model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
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;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media;
|
||||
|
||||
public class CreateMediaController : MediaControllerBase
|
||||
{
|
||||
private readonly IMediaEditingService _mediaEditingService;
|
||||
private readonly IMediaEditingPresentationFactory _mediaEditingPresentationFactory;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public CreateMediaController(IMediaEditingService mediaEditingService, IMediaEditingPresentationFactory mediaEditingPresentationFactory, IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_mediaEditingService = mediaEditingService;
|
||||
_mediaEditingPresentationFactory = mediaEditingPresentationFactory;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Create(CreateMediaRequestModel createRequestModel)
|
||||
{
|
||||
MediaCreateModel model = _mediaEditingPresentationFactory.MapCreateModel(createRequestModel);
|
||||
Attempt<IMedia?, ContentEditingOperationStatus> result = await _mediaEditingService.CreateAsync(model, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
|
||||
return result.Success
|
||||
? CreatedAtAction<ByKeyMediaController>(controller => nameof(controller.ByKey), result.Result!.Key)
|
||||
: ContentEditingOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Content;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
[ApiController]
|
||||
[VersionedApiBackOfficeRoute(Constants.UdiEntityType.Media)]
|
||||
[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Media))]
|
||||
public class MediaControllerBase : ContentControllerBase
|
||||
{
|
||||
protected IActionResult MediaNotFound() => NotFound("The requested Media could not be found");
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media;
|
||||
|
||||
public class MoveToRecycleBinMediaController : MediaControllerBase
|
||||
{
|
||||
private readonly IMediaEditingService _mediaEditingService;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public MoveToRecycleBinMediaController(IMediaEditingService mediaEditingService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_mediaEditingService = mediaEditingService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpDelete("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> MoveToRecycleBin(Guid key)
|
||||
{
|
||||
Attempt<IMedia?, ContentEditingOperationStatus> result = await _mediaEditingService.MoveToRecycleBinAsync(key, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
return result.Success
|
||||
? Ok()
|
||||
: ContentEditingOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
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;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media;
|
||||
|
||||
public class UpdateMediaController : MediaControllerBase
|
||||
{
|
||||
private readonly IMediaEditingService _mediaEditingService;
|
||||
private readonly IMediaEditingPresentationFactory _mediaEditingPresentationFactory;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public UpdateMediaController(
|
||||
IMediaEditingService mediaEditingService,
|
||||
IMediaEditingPresentationFactory mediaEditingPresentationFactory,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_mediaEditingService = mediaEditingService;
|
||||
_mediaEditingPresentationFactory = mediaEditingPresentationFactory;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpPut("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Update(Guid key, UpdateMediaRequestModel updateRequestModel)
|
||||
{
|
||||
IMedia? media = await _mediaEditingService.GetAsync(key);
|
||||
if (media == null)
|
||||
{
|
||||
return MediaNotFound();
|
||||
}
|
||||
|
||||
MediaUpdateModel model = _mediaEditingPresentationFactory.MapUpdateModel(updateRequestModel);
|
||||
Attempt<IMedia, ContentEditingOperationStatus> result = await _mediaEditingService.UpdateAsync(media, model, CurrentUserId(_backOfficeSecurityAccessor));
|
||||
|
||||
return result.Success
|
||||
? Ok()
|
||||
: ContentEditingOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.MediaType;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.MediaType;
|
||||
|
||||
public class ByKeyMediaTypeController : MediaTypeControllerBase
|
||||
{
|
||||
private readonly IMediaTypeService _mediaTypeService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public ByKeyMediaTypeController(IMediaTypeService mediaTypeService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_mediaTypeService = mediaTypeService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
[HttpGet("{key:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(MediaTypeResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ByKey(Guid key)
|
||||
{
|
||||
// FIXME: create and use an async get method here.
|
||||
IMediaType? mediaType = _mediaTypeService.Get(key);
|
||||
if (mediaType == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
MediaTypeResponseModel model = _umbracoMapper.Map<MediaTypeResponseModel>(mediaType)!;
|
||||
return await Task.FromResult(Ok(model));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.MediaType;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
[ApiController]
|
||||
[VersionedApiBackOfficeRoute(Constants.UdiEntityType.MediaType)]
|
||||
[ApiExplorerSettings(GroupName = "Media Type")]
|
||||
public abstract class MediaTypeControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.Mapping.Media;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.DependencyInjection;
|
||||
|
||||
internal static class MediaBuilderExtensions
|
||||
{
|
||||
internal static IUmbracoBuilder AddMedia(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddTransient<IMediaPresentationModelFactory, MediaPresentationModelFactory>();
|
||||
builder.Services.AddTransient<IMediaEditingPresentationFactory, MediaEditingPresentationFactory>();
|
||||
|
||||
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>().Add<MediaMapDefinition>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Umbraco.Cms.Api.Management.Mapping.MediaType;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.DependencyInjection;
|
||||
|
||||
internal static class MediaTypeBuilderExtensions
|
||||
{
|
||||
internal static IUmbracoBuilder AddMediaTypes(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>().Add<MediaTypeMapDefinition>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public interface IMediaEditingPresentationFactory
|
||||
{
|
||||
MediaCreateModel MapCreateModel(CreateMediaRequestModel createRequestModel);
|
||||
|
||||
MediaUpdateModel MapUpdateModel(UpdateMediaRequestModel updateRequestModel);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public interface IMediaPresentationModelFactory
|
||||
{
|
||||
Task<MediaResponseModel> CreateResponseModelAsync(IMedia media);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
internal sealed class MediaEditingPresentationFactory : ContentEditingPresentationFactory<MediaValueModel, MediaVariantRequestModel>, IMediaEditingPresentationFactory
|
||||
{
|
||||
public MediaCreateModel MapCreateModel(CreateMediaRequestModel createRequestModel)
|
||||
{
|
||||
MediaCreateModel model = MapContentEditingModel<MediaCreateModel>(createRequestModel);
|
||||
model.ContentTypeKey = createRequestModel.ContentTypeKey;
|
||||
model.ParentKey = createRequestModel.ParentKey;
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public MediaUpdateModel MapUpdateModel(UpdateMediaRequestModel updateRequestModel)
|
||||
{
|
||||
MediaUpdateModel model = MapContentEditingModel<MediaUpdateModel>(updateRequestModel);
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public class MediaPresentationModelFactory : IMediaPresentationModelFactory
|
||||
{
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
private readonly ContentSettings _contentSettings;
|
||||
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
|
||||
|
||||
public MediaPresentationModelFactory(IUmbracoMapper umbracoMapper, IOptions<ContentSettings> contentSettings, MediaUrlGeneratorCollection mediaUrlGenerators)
|
||||
{
|
||||
_umbracoMapper = umbracoMapper;
|
||||
_contentSettings = contentSettings.Value;
|
||||
_mediaUrlGenerators = mediaUrlGenerators;
|
||||
}
|
||||
|
||||
public Task<MediaResponseModel> CreateResponseModelAsync(IMedia media)
|
||||
{
|
||||
MediaResponseModel responseModel = _umbracoMapper.Map<MediaResponseModel>(media)!;
|
||||
|
||||
responseModel.Urls = media
|
||||
.GetUrls(_contentSettings, _mediaUrlGenerators)
|
||||
.WhereNotNull()
|
||||
.Select(mediaUrl => new ContentUrlInfo
|
||||
{
|
||||
Culture = null,
|
||||
Url = mediaUrl
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
return Task.FromResult(responseModel);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ public class ManagementApiComposer : IComposer
|
||||
.AddAuditLogs()
|
||||
.AddDocuments()
|
||||
.AddDocumentTypes()
|
||||
.AddMedia()
|
||||
.AddMediaTypes()
|
||||
.AddLanguages()
|
||||
.AddDictionary()
|
||||
.AddFileUpload()
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
using ContentTypeSort = Umbraco.Cms.Api.Management.ViewModels.ContentType.ContentTypeSort;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Mapping.ContentType;
|
||||
|
||||
public abstract class ContentTypeMapDefinition<TContentType, TPropertyTypeViewModel, TPropertyTypeContainerViewModel>
|
||||
public abstract class ContentTypeMapDefinition<TContentType, TPropertyTypeResponseModel, TPropertyTypeContainerResponseModel>
|
||||
where TContentType : IContentTypeBase
|
||||
where TPropertyTypeViewModel : PropertyTypePresentationBase, new()
|
||||
where TPropertyTypeContainerViewModel : PropertyTypeContainerPresentationBase, new()
|
||||
where TPropertyTypeResponseModel : PropertyTypeResponseModelBase, new()
|
||||
where TPropertyTypeContainerResponseModel : PropertyTypeContainerResponseModelBase, new()
|
||||
{
|
||||
protected IEnumerable<TPropertyTypeViewModel> MapPropertyTypes(TContentType source)
|
||||
protected IEnumerable<TPropertyTypeResponseModel> MapPropertyTypes(TContentType source)
|
||||
{
|
||||
// create a mapping table between properties and their associated groups
|
||||
var groupKeysByPropertyKeys = source
|
||||
@@ -20,7 +21,7 @@ public abstract class ContentTypeMapDefinition<TContentType, TPropertyTypeViewMo
|
||||
.ToDictionary(map => map.PropertyTypeKey, map => map.GroupKey);
|
||||
|
||||
return source.PropertyTypes.Select(propertyType =>
|
||||
new TPropertyTypeViewModel
|
||||
new TPropertyTypeResponseModel
|
||||
{
|
||||
Key = propertyType.Key,
|
||||
ContainerKey = groupKeysByPropertyKeys.ContainsKey(propertyType.Key)
|
||||
@@ -47,7 +48,7 @@ public abstract class ContentTypeMapDefinition<TContentType, TPropertyTypeViewMo
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected IEnumerable<TPropertyTypeContainerViewModel> MapPropertyTypeContainers(TContentType source)
|
||||
protected IEnumerable<TPropertyTypeContainerResponseModel> MapPropertyTypeContainers(TContentType source)
|
||||
{
|
||||
// create a mapping table between property group aliases and keys
|
||||
var groupKeysByGroupAliases = source
|
||||
@@ -65,7 +66,7 @@ public abstract class ContentTypeMapDefinition<TContentType, TPropertyTypeViewMo
|
||||
return source
|
||||
.PropertyGroups
|
||||
.Select(propertyGroup =>
|
||||
new TPropertyTypeContainerViewModel
|
||||
new TPropertyTypeContainerResponseModel
|
||||
{
|
||||
Key = propertyGroup.Key,
|
||||
ParentKey = ParentGroupKey(propertyGroup),
|
||||
@@ -75,4 +76,17 @@ public abstract class ContentTypeMapDefinition<TContentType, TPropertyTypeViewMo
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected IEnumerable<ContentTypeSort> MapAllowedContentTypes(TContentType source)
|
||||
=> source.AllowedContentTypes?.Select(contentTypeSort => new ContentTypeSort { Key = contentTypeSort.Key, SortOrder = contentTypeSort.SortOrder }).ToArray()
|
||||
?? Array.Empty<ContentTypeSort>();
|
||||
|
||||
protected IEnumerable<ContentTypeComposition> MapCompositions(TContentType source, IEnumerable<IContentTypeComposition> contentTypeComposition)
|
||||
=> contentTypeComposition.Select(contentType => new ContentTypeComposition
|
||||
{
|
||||
Key = contentType.Key,
|
||||
CompositionType = contentType.Id == source.ParentId
|
||||
? ContentTypeCompositionType.Inheritance
|
||||
: ContentTypeCompositionType.Composition
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
@@ -4,11 +4,10 @@ using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
using ContentTypeSort = Umbraco.Cms.Api.Management.ViewModels.ContentType.ContentTypeSort;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Mapping.DocumentType;
|
||||
|
||||
public class DocumentTypeMapDefinition : ContentTypeMapDefinition<IContentType, DocumentTypePropertyTypePresentationBase, DocumentTypePropertyTypeContainerPresentationBase>, IMapDefinition
|
||||
public class DocumentTypeMapDefinition : ContentTypeMapDefinition<IContentType, DocumentTypePropertyTypeResponseModel, DocumentTypePropertyTypeContainerResponseModel>, IMapDefinition
|
||||
{
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
=> mapper.Define<IContentType, DocumentTypeResponseModel>((_, _) => new DocumentTypeResponseModel(), Map);
|
||||
@@ -27,12 +26,8 @@ public class DocumentTypeMapDefinition : ContentTypeMapDefinition<IContentType,
|
||||
target.IsElement = source.IsElement;
|
||||
target.Containers = MapPropertyTypeContainers(source);
|
||||
target.Properties = MapPropertyTypes(source);
|
||||
|
||||
if (source.AllowedContentTypes != null)
|
||||
{
|
||||
target.AllowedContentTypes = source.AllowedContentTypes.Select(contentTypeSort
|
||||
=> new ContentTypeSort { Key = contentTypeSort.Key, SortOrder = contentTypeSort.SortOrder });
|
||||
}
|
||||
target.AllowedContentTypes = MapAllowedContentTypes(source);
|
||||
target.Compositions = MapCompositions(source, source.ContentTypeComposition);
|
||||
|
||||
if (source.AllowedTemplates != null)
|
||||
{
|
||||
@@ -50,13 +45,5 @@ public class DocumentTypeMapDefinition : ContentTypeMapDefinition<IContentType,
|
||||
KeepLatestVersionPerDayForDays = source.HistoryCleanup.KeepLatestVersionPerDayForDays
|
||||
};
|
||||
}
|
||||
|
||||
target.Compositions = source.ContentTypeComposition.Select(contentType => new ContentTypeComposition
|
||||
{
|
||||
Key = contentType.Key,
|
||||
CompositionType = contentType.Id == source.ParentId
|
||||
? ContentTypeCompositionType.Inheritance
|
||||
: ContentTypeCompositionType.Composition
|
||||
}).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using Umbraco.Cms.Api.Management.Mapping.Content;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Mapping.Media;
|
||||
|
||||
public class MediaMapDefinition : ContentMapDefinition<IMedia, MediaValueModel, MediaVariantResponseModel>, IMapDefinition
|
||||
{
|
||||
public MediaMapDefinition(PropertyEditorCollection propertyEditorCollection)
|
||||
: base(propertyEditorCollection)
|
||||
{
|
||||
}
|
||||
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
=> mapper.Define<IMedia, MediaResponseModel>((_, _) => new MediaResponseModel(), Map);
|
||||
|
||||
// Umbraco.Code.MapAll -Urls
|
||||
private void Map(IMedia source, MediaResponseModel target, MapperContext context)
|
||||
{
|
||||
target.Key = source.Key;
|
||||
target.ContentTypeKey = source.ContentType.Key;
|
||||
target.Values = MapValueViewModels(source);
|
||||
target.Variants = MapVariantViewModels(source);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Umbraco.Cms.Api.Management.Mapping.ContentType;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.MediaType;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Mapping.MediaType;
|
||||
|
||||
public class MediaTypeMapDefinition : ContentTypeMapDefinition<IMediaType, MediaTypePropertyTypeResponseModel, MediaTypePropertyTypeContainerResponseModel>, IMapDefinition
|
||||
{
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
=> mapper.Define<IMediaType, MediaTypeResponseModel>((_, _) => new MediaTypeResponseModel(), Map);
|
||||
|
||||
// Umbraco.Code.MapAll
|
||||
private void Map(IMediaType source, MediaTypeResponseModel target, MapperContext context)
|
||||
{
|
||||
target.Key = source.Key;
|
||||
target.Alias = source.Alias;
|
||||
target.Name = source.Name ?? string.Empty;
|
||||
target.Description = source.Description;
|
||||
target.Icon = source.Icon ?? string.Empty;
|
||||
target.AllowedAsRoot = source.AllowedAsRoot;
|
||||
target.VariesByCulture = source.VariesByCulture();
|
||||
target.VariesBySegment = source.VariesBySegment();
|
||||
target.IsElement = source.IsElement;
|
||||
target.Containers = MapPropertyTypeContainers(source);
|
||||
target.Properties = MapPropertyTypes(source);
|
||||
target.AllowedContentTypes = MapAllowedContentTypes(source);
|
||||
target.Compositions = MapCompositions(source, source.ContentTypeComposition);
|
||||
}
|
||||
}
|
||||
@@ -3127,6 +3127,44 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/media-type/{key}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Media Type"
|
||||
],
|
||||
"operationId": "GetMediaTypeByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaTypeResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/tree/media-type/children": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -3274,6 +3312,155 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/media": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Media"
|
||||
],
|
||||
"operationId": "PostMedia",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/CreateMediaRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "Created",
|
||||
"headers": {
|
||||
"Location": {
|
||||
"description": "Location of the newly created resource",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"description": "Location of the newly created resource",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/media/{key}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Media"
|
||||
],
|
||||
"operationId": "GetMediaByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"tags": [
|
||||
"Media"
|
||||
],
|
||||
"operationId": "DeleteMediaByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"tags": [
|
||||
"Media"
|
||||
],
|
||||
"operationId": "PutMediaByKey",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "key",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/UpdateMediaRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success"
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/recycle-bin/media/children": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -6560,37 +6747,6 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContentCreateRequestModelBaseDocumentValueModelDocumentVariantRequestModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentValueModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVariantRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parentKey": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContentResponseModelBaseDocumentValueModelDocumentVariantResponseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6705,7 +6861,7 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"ContentTypePresentationBaseDocumentTypePropertyTypePresentationBaseDocumentTypePropertyTypeContainerPresentationBaseModel": {
|
||||
"ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDocumentTypePropertyTypeContainerResponseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
@@ -6742,7 +6898,7 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypePropertyTypePresentationBaseModel"
|
||||
"$ref": "#/components/schemas/DocumentTypePropertyTypeResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6752,7 +6908,7 @@
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypePropertyTypeContainerPresentationBaseModel"
|
||||
"$ref": "#/components/schemas/DocumentTypePropertyTypeContainerResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6776,13 +6932,81 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaTypePropertyTypeContainerResponseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"cleanup": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentTypeCleanupModel"
|
||||
}
|
||||
]
|
||||
"alias": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"allowedAsRoot": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"variesByCulture": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"variesBySegment": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isElement": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"properties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaTypePropertyTypeResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"containers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaTypePropertyTypeContainerResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"allowedContentTypes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentTypeSortModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"compositions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentTypeCompositionModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -6801,32 +7025,6 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContentUpdateRequestModelBaseDocumentValueModelDocumentVariantRequestModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentValueModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVariantRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"ContentUrlInfoModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -6851,6 +7049,68 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CreateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentValueModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVariantRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parentKey": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CreateContentRequestModelBaseMediaValueModelMediaVariantRequestModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaValueModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaVariantRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parentKey": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CreateDataTypeRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
@@ -6887,7 +7147,7 @@
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentCreateRequestModelBaseDocumentValueModelDocumentVariantRequestModel"
|
||||
"$ref": "#/components/schemas/CreateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
@@ -6933,6 +7193,21 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CreateMediaRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/CreateContentRequestModelBaseMediaValueModelMediaVariantRequestModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"contentTypeKey": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"CreatePackageRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
@@ -7349,20 +7624,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"DocumentTypePropertyTypeContainerPresentationBaseModel": {
|
||||
"DocumentTypePropertyTypeContainerResponseModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PropertyTypeContainerPresentationBaseModel"
|
||||
"$ref": "#/components/schemas/PropertyTypeContainerResponseModelBaseModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"DocumentTypePropertyTypePresentationBaseModel": {
|
||||
"DocumentTypePropertyTypeResponseModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PropertyTypePresentationBaseModel"
|
||||
"$ref": "#/components/schemas/PropertyTypeResponseModelBaseModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
@@ -7371,7 +7646,7 @@
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentTypePresentationBaseDocumentTypePropertyTypePresentationBaseDocumentTypePropertyTypeContainerPresentationBaseModel"
|
||||
"$ref": "#/components/schemas/ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDocumentTypePropertyTypeContainerResponseModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
@@ -7386,6 +7661,13 @@
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
},
|
||||
"cleanup": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentTypeCleanupModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -8099,6 +8381,102 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MediaTypePropertyTypeContainerResponseModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PropertyTypeContainerResponseModelBaseModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MediaTypePropertyTypeResponseModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PropertyTypeResponseModelBaseModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MediaTypeResponseModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaTypePropertyTypeContainerResponseModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MediaValueModel": {
|
||||
"required": [
|
||||
"$type"
|
||||
],
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ValueModelBaseModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"$type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"discriminator": {
|
||||
"propertyName": "$type",
|
||||
"mapping": {
|
||||
"MediaValueModel": "#/components/schemas/MediaValueModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MediaVariantRequestModel": {
|
||||
"required": [
|
||||
"$type"
|
||||
],
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/VariantModelBaseModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"$type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"discriminator": {
|
||||
"propertyName": "$type",
|
||||
"mapping": {
|
||||
"MediaVariantRequestModel": "#/components/schemas/MediaVariantRequestModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MediaVariantResponseModel": {
|
||||
"required": [
|
||||
"$type"
|
||||
],
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/VariantResponseModelBaseModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"$type": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"discriminator": {
|
||||
"propertyName": "$type",
|
||||
"mapping": {
|
||||
"MediaVariantResponseModel": "#/components/schemas/MediaVariantResponseModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ModelsBuilderResponseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -9139,7 +9517,7 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PropertyTypeContainerPresentationBaseModel": {
|
||||
"PropertyTypeContainerResponseModelBaseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
@@ -9165,7 +9543,7 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PropertyTypePresentationBaseModel": {
|
||||
"PropertyTypeResponseModelBaseModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
@@ -9843,6 +10221,58 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UpdateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentValueModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVariantRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UpdateContentRequestModelBaseMediaValueModelMediaVariantRequestModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaValueModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"variants": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaVariantRequestModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UpdateDataTypeRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
@@ -9865,7 +10295,7 @@
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentUpdateRequestModelBaseDocumentValueModelDocumentVariantRequestModel"
|
||||
"$ref": "#/components/schemas/UpdateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
@@ -9895,6 +10325,15 @@
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UpdateMediaRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/UpdateContentRequestModelBaseMediaValueModelMediaVariantRequestModel"
|
||||
}
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"UpdatePackageRequestModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
@@ -10131,6 +10570,7 @@
|
||||
"discriminator": {
|
||||
"propertyName": "$type",
|
||||
"mapping": {
|
||||
"MediaValueModel": "#/components/schemas/MediaValueModel",
|
||||
"DocumentValueModel": "#/components/schemas/DocumentValueModel"
|
||||
}
|
||||
}
|
||||
@@ -10160,6 +10600,8 @@
|
||||
"discriminator": {
|
||||
"propertyName": "$type",
|
||||
"mapping": {
|
||||
"MediaVariantRequestModel": "#/components/schemas/MediaVariantRequestModel",
|
||||
"MediaVariantResponseModel": "#/components/schemas/MediaVariantResponseModel",
|
||||
"DocumentVariantRequestModel": "#/components/schemas/DocumentVariantRequestModel",
|
||||
"DocumentVariantResponseModel": "#/components/schemas/DocumentVariantResponseModel"
|
||||
}
|
||||
@@ -10198,6 +10640,7 @@
|
||||
"discriminator": {
|
||||
"propertyName": "$type",
|
||||
"mapping": {
|
||||
"MediaVariantResponseModel": "#/components/schemas/MediaVariantResponseModel",
|
||||
"DocumentVariantResponseModel": "#/components/schemas/DocumentVariantResponseModel"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
public abstract class ContentCreateRequestModelBase<TValueModel, TVariantModel>
|
||||
public abstract class CreateContentRequestModelBase<TValueModel, TVariantModel>
|
||||
: ContentModelBase<TValueModel, TVariantModel>
|
||||
where TValueModel : ValueModelBase
|
||||
where TVariantModel : VariantModelBase
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
public abstract class ContentUpdateRequestModelBase<TValueModel, TVariantModel>
|
||||
public abstract class UpdateContentRequestModelBase<TValueModel, TVariantModel>
|
||||
: ContentModelBase<TValueModel, TVariantModel>
|
||||
where TValueModel : ValueModelBase
|
||||
where TVariantModel : VariantModelBase
|
||||
@@ -1,8 +1,8 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.ContentType;
|
||||
|
||||
public abstract class ContentTypePresentationBase<TPropertyType, TPropertyTypeContainer>
|
||||
where TPropertyType : PropertyTypePresentationBase
|
||||
where TPropertyTypeContainer : PropertyTypeContainerPresentationBase
|
||||
public abstract class ContentTypeResponseModelBase<TPropertyType, TPropertyTypeContainer>
|
||||
where TPropertyType : PropertyTypeResponseModelBase
|
||||
where TPropertyTypeContainer : PropertyTypeContainerResponseModelBase
|
||||
{
|
||||
public Guid Key { get; set; }
|
||||
|
||||
@@ -29,6 +29,4 @@ public abstract class ContentTypePresentationBase<TPropertyType, TPropertyTypeCo
|
||||
public IEnumerable<ContentTypeSort> AllowedContentTypes { get; set; } = Array.Empty<ContentTypeSort>();
|
||||
|
||||
public IEnumerable<ContentTypeComposition> Compositions { get; set; } = Array.Empty<ContentTypeComposition>();
|
||||
|
||||
public ContentTypeCleanup Cleanup { get; set; } = new();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.ContentType;
|
||||
|
||||
public abstract class PropertyTypeContainerPresentationBase
|
||||
public abstract class PropertyTypeContainerResponseModelBase
|
||||
{
|
||||
public Guid Key { get; set; }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.ContentType;
|
||||
|
||||
public abstract class PropertyTypePresentationBase
|
||||
public abstract class PropertyTypeResponseModelBase
|
||||
{
|
||||
public Guid Key { get; set; }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
|
||||
public class CreateDocumentRequestModel : ContentCreateRequestModelBase<DocumentValueModel, DocumentVariantRequestModel>
|
||||
public class CreateDocumentRequestModel : CreateContentRequestModelBase<DocumentValueModel, DocumentVariantRequestModel>
|
||||
{
|
||||
public Guid ContentTypeKey { get; set; }
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
|
||||
public class UpdateDocumentRequestModel : ContentUpdateRequestModelBase<DocumentValueModel, DocumentVariantRequestModel>
|
||||
public class UpdateDocumentRequestModel : UpdateContentRequestModelBase<DocumentValueModel, DocumentVariantRequestModel>
|
||||
{
|
||||
public Guid? TemplateKey { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
|
||||
public class DocumentTypePropertyTypeContainerPresentationBase : PropertyTypeContainerPresentationBase
|
||||
public class DocumentTypePropertyTypeContainerResponseModel : PropertyTypeContainerResponseModelBase
|
||||
{
|
||||
}
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
|
||||
public class DocumentTypePropertyTypePresentationBase : PropertyTypePresentationBase
|
||||
public class DocumentTypePropertyTypeResponseModel : PropertyTypeResponseModelBase
|
||||
{
|
||||
}
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
|
||||
public class DocumentTypeResponseModel : ContentTypePresentationBase<DocumentTypePropertyTypePresentationBase, DocumentTypePropertyTypeContainerPresentationBase>
|
||||
public class DocumentTypeResponseModel : ContentTypeResponseModelBase<DocumentTypePropertyTypeResponseModel, DocumentTypePropertyTypeContainerResponseModel>
|
||||
{
|
||||
public IEnumerable<Guid> AllowedTemplateKeys { get; set; } = Array.Empty<Guid>();
|
||||
|
||||
public Guid? DefaultTemplateKey { get; set; }
|
||||
|
||||
public ContentTypeCleanup Cleanup { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
|
||||
public class CreateMediaRequestModel : CreateContentRequestModelBase<MediaValueModel, MediaVariantRequestModel>
|
||||
{
|
||||
public Guid ContentTypeKey { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
|
||||
public class MediaResponseModel : ContentResponseModelBase<MediaValueModel, MediaVariantResponseModel>
|
||||
{
|
||||
public IEnumerable<ContentUrlInfo> Urls { get; set; } = Array.Empty<ContentUrlInfo>();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
|
||||
public class MediaValueModel : ValueModelBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
|
||||
public class MediaVariantRequestModel : VariantModelBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
|
||||
public class MediaVariantResponseModel : VariantResponseModelBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
|
||||
public class UpdateMediaRequestModel : UpdateContentRequestModelBase<MediaValueModel, MediaVariantRequestModel>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.ContentType;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.MediaType;
|
||||
|
||||
public class MediaTypePropertyTypeContainerResponseModel : PropertyTypeContainerResponseModelBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.ContentType;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.MediaType;
|
||||
|
||||
public class MediaTypePropertyTypeResponseModel : PropertyTypeResponseModelBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.ContentType;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.MediaType;
|
||||
|
||||
public class MediaTypeResponseModel : ContentTypeResponseModelBase<MediaTypePropertyTypeResponseModel, MediaTypePropertyTypeContainerResponseModel>
|
||||
{
|
||||
}
|
||||
@@ -299,6 +299,7 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
Services.AddUnique<IContentVersionCleanupPolicy, DefaultContentVersionCleanupPolicy>();
|
||||
Services.AddUnique<IMemberService, MemberService>();
|
||||
Services.AddUnique<IMediaService, MediaService>();
|
||||
Services.AddUnique<IMediaEditingService, MediaEditingService>();
|
||||
Services.AddUnique<IContentTypeService, ContentTypeService>();
|
||||
Services.AddUnique<IContentTypeBaseServiceProvider, ContentTypeBaseServiceProvider>();
|
||||
Services.AddUnique<IMediaTypeService, MediaTypeService>();
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
public class MediaCreateModel : ContentCreationModelBase
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
public class MediaUpdateModel : ContentEditingModelBase
|
||||
{
|
||||
}
|
||||
@@ -12,7 +12,6 @@ internal sealed class ContentEditingService
|
||||
{
|
||||
private readonly ITemplateService _templateService;
|
||||
private readonly ILogger<ContentEditingService> _logger;
|
||||
private readonly ICoreScopeProvider _scopeProvider;
|
||||
|
||||
public ContentEditingService(
|
||||
IContentService contentService,
|
||||
@@ -22,11 +21,10 @@ internal sealed class ContentEditingService
|
||||
ITemplateService templateService,
|
||||
ILogger<ContentEditingService> logger,
|
||||
ICoreScopeProvider scopeProvider)
|
||||
: base(contentService, contentTypeService, propertyEditorCollection, dataTypeService, logger)
|
||||
: base(contentService, contentTypeService, propertyEditorCollection, dataTypeService, logger, scopeProvider)
|
||||
{
|
||||
_templateService = templateService;
|
||||
_logger = logger;
|
||||
_scopeProvider = scopeProvider;
|
||||
}
|
||||
|
||||
public async Task<IContent?> GetAsync(Guid id)
|
||||
@@ -77,10 +75,10 @@ internal sealed class ContentEditingService
|
||||
}
|
||||
|
||||
public async Task<Attempt<IContent?, ContentEditingOperationStatus>> MoveToRecycleBinAsync(Guid id, int userId = Constants.Security.SuperUserId)
|
||||
=> await HandleDeletionAsync(id, content => ContentService.MoveToRecycleBin(content, userId));
|
||||
=> await HandleDeletionAsync(id, content => ContentService.MoveToRecycleBin(content, userId), false);
|
||||
|
||||
public async Task<Attempt<IContent?, ContentEditingOperationStatus>> DeleteAsync(Guid id, int userId = Constants.Security.SuperUserId)
|
||||
=> await HandleDeletionAsync(id, content => ContentService.Delete(content, userId));
|
||||
=> await HandleDeletionAsync(id, content => ContentService.Delete(content, userId), true);
|
||||
|
||||
protected override IContent Create(string? name, int parentId, IContentType contentType) => new Content(name, parentId, contentType);
|
||||
|
||||
@@ -130,26 +128,4 @@ internal sealed class ContentEditingService
|
||||
return ContentEditingOperationStatus.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
// helper method to perform move-to-recycle-bin and delete for content as they are very much handled in the same way
|
||||
private async Task<Attempt<IContent?, ContentEditingOperationStatus>> HandleDeletionAsync(Guid id, Func<IContent, OperationResult> performDelete)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete:true);
|
||||
IContent? content = ContentService.GetById(id);
|
||||
if (content == null)
|
||||
{
|
||||
return await Task.FromResult(Attempt.FailWithStatus(ContentEditingOperationStatus.NotFound, content));
|
||||
}
|
||||
|
||||
OperationResult deleteResult = performDelete(content);
|
||||
return deleteResult.Result switch
|
||||
{
|
||||
// these are the only result states currently expected from Delete
|
||||
OperationResultType.Success => Attempt.SucceedWithStatus<IContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.Success, content),
|
||||
OperationResultType.FailedCancelledByEvent => Attempt.FailWithStatus<IContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.CancelledByNotification, content),
|
||||
|
||||
// for any other state we'll return "unknown" so we know that we need to amend this
|
||||
_ => Attempt.FailWithStatus<IContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.Unknown, content)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.Editors;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -20,16 +21,20 @@ public abstract class ContentEditingServiceBase<TContent, TContentType, TContent
|
||||
|
||||
private readonly ILogger<ContentEditingServiceBase<TContent, TContentType, TContentService, TContentTypeService>> _logger;
|
||||
|
||||
private readonly ICoreScopeProvider _scopeProvider;
|
||||
|
||||
protected ContentEditingServiceBase(
|
||||
TContentService contentService,
|
||||
TContentTypeService contentTypeService,
|
||||
PropertyEditorCollection propertyEditorCollection,
|
||||
IDataTypeService dataTypeService,
|
||||
ILogger<ContentEditingServiceBase<TContent, TContentType, TContentService, TContentTypeService>> logger)
|
||||
ILogger<ContentEditingServiceBase<TContent, TContentType, TContentService, TContentTypeService>> logger,
|
||||
ICoreScopeProvider scopeProvider)
|
||||
{
|
||||
_propertyEditorCollection = propertyEditorCollection;
|
||||
_dataTypeService = dataTypeService;
|
||||
_logger = logger;
|
||||
_scopeProvider = scopeProvider;
|
||||
ContentService = contentService;
|
||||
ContentTypeService = contentTypeService;
|
||||
}
|
||||
@@ -77,6 +82,33 @@ public abstract class ContentEditingServiceBase<TContent, TContentType, TContent
|
||||
return Attempt.Succeed(ContentEditingOperationStatus.Success);
|
||||
}
|
||||
|
||||
// helper method to perform move-to-recycle-bin and delete for content as they are very much handled in the same way
|
||||
protected async Task<Attempt<TContent?, ContentEditingOperationStatus>> HandleDeletionAsync(Guid id, Func<TContent, OperationResult?> performDelete, bool allowForTrashed)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete:true);
|
||||
TContent? content = ContentService.GetById(id);
|
||||
if (content == null)
|
||||
{
|
||||
return await Task.FromResult(Attempt.FailWithStatus(ContentEditingOperationStatus.NotFound, content));
|
||||
}
|
||||
|
||||
if (content.Trashed && allowForTrashed is false)
|
||||
{
|
||||
return await Task.FromResult(Attempt.FailWithStatus<TContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.InTrash, content));
|
||||
}
|
||||
|
||||
OperationResult? deleteResult = performDelete(content);
|
||||
return deleteResult?.Result switch
|
||||
{
|
||||
// these are the only result states currently expected from Delete
|
||||
OperationResultType.Success => Attempt.SucceedWithStatus<TContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.Success, content),
|
||||
OperationResultType.FailedCancelledByEvent => Attempt.FailWithStatus<TContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.CancelledByNotification, content),
|
||||
|
||||
// for any other state we'll return "unknown" so we know that we need to amend this
|
||||
_ => Attempt.FailWithStatus<TContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.Unknown, content)
|
||||
};
|
||||
}
|
||||
|
||||
private TContentType? TryGetAndValidateContentType(Guid contentTypeKey, ContentEditingModelBase contentEditingModelBase, out ContentEditingOperationStatus operationStatus)
|
||||
{
|
||||
TContentType? contentType = ContentTypeService.Get(contentTypeKey);
|
||||
|
||||
18
src/Umbraco.Core/Services/IMediaEditingService.cs
Normal file
18
src/Umbraco.Core/Services/IMediaEditingService.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
public interface IMediaEditingService
|
||||
{
|
||||
Task<IMedia?> GetAsync(Guid id);
|
||||
|
||||
Task<Attempt<IMedia?, ContentEditingOperationStatus>> CreateAsync(MediaCreateModel createModel, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
Task<Attempt<IMedia, ContentEditingOperationStatus>> UpdateAsync(IMedia content, MediaUpdateModel updateModel, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
Task<Attempt<IMedia?, ContentEditingOperationStatus>> MoveToRecycleBinAsync(Guid id, int userId = Constants.Security.SuperUserId);
|
||||
|
||||
Task<Attempt<IMedia?, ContentEditingOperationStatus>> DeleteAsync(Guid id, int userId = Constants.Security.SuperUserId);
|
||||
}
|
||||
91
src/Umbraco.Core/Services/MediaEditingService.cs
Normal file
91
src/Umbraco.Core/Services/MediaEditingService.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
internal sealed class MediaEditingService
|
||||
: ContentEditingServiceBase<IMedia, IMediaType, IMediaService, IMediaTypeService>, IMediaEditingService
|
||||
{
|
||||
private readonly ILogger<ContentEditingServiceBase<IMedia, IMediaType, IMediaService, IMediaTypeService>> _logger;
|
||||
|
||||
public MediaEditingService(
|
||||
IMediaService contentService,
|
||||
IMediaTypeService contentTypeService,
|
||||
PropertyEditorCollection propertyEditorCollection,
|
||||
IDataTypeService dataTypeService,
|
||||
ILogger<ContentEditingServiceBase<IMedia, IMediaType, IMediaService, IMediaTypeService>> logger,
|
||||
ICoreScopeProvider scopeProvider)
|
||||
: base(contentService, contentTypeService, propertyEditorCollection, dataTypeService, logger, scopeProvider) =>
|
||||
_logger = logger;
|
||||
|
||||
public async Task<IMedia?> GetAsync(Guid id)
|
||||
{
|
||||
IMedia? media = ContentService.GetById(id);
|
||||
return await Task.FromResult(media);
|
||||
}
|
||||
|
||||
public async Task<Attempt<IMedia?, ContentEditingOperationStatus>> CreateAsync(MediaCreateModel createModel, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
Attempt<IMedia?, ContentEditingOperationStatus> result = await MapCreate(createModel);
|
||||
if (result.Success == false)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
IMedia media = result.Result!;
|
||||
|
||||
ContentEditingOperationStatus operationStatus = Save(media, userId);
|
||||
return operationStatus == ContentEditingOperationStatus.Success
|
||||
? Attempt.SucceedWithStatus<IMedia?, ContentEditingOperationStatus>(ContentEditingOperationStatus.Success, media)
|
||||
: Attempt.FailWithStatus<IMedia?, ContentEditingOperationStatus>(operationStatus, media);
|
||||
}
|
||||
|
||||
public async Task<Attempt<IMedia, ContentEditingOperationStatus>> UpdateAsync(IMedia content, MediaUpdateModel updateModel, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
Attempt<ContentEditingOperationStatus> result = await MapUpdate(content, updateModel);
|
||||
if (result.Success == false)
|
||||
{
|
||||
return Attempt.FailWithStatus(result.Result, content);
|
||||
}
|
||||
|
||||
ContentEditingOperationStatus operationStatus = Save(content, userId);
|
||||
return operationStatus == ContentEditingOperationStatus.Success
|
||||
? Attempt.SucceedWithStatus(ContentEditingOperationStatus.Success, content)
|
||||
: Attempt.FailWithStatus(operationStatus, content);
|
||||
}
|
||||
|
||||
public async Task<Attempt<IMedia?, ContentEditingOperationStatus>> MoveToRecycleBinAsync(Guid id, int userId = Constants.Security.SuperUserId)
|
||||
=> await HandleDeletionAsync(id, media => ContentService.MoveToRecycleBin(media, userId).Result, false);
|
||||
|
||||
public async Task<Attempt<IMedia?, ContentEditingOperationStatus>> DeleteAsync(Guid id, int userId = Constants.Security.SuperUserId)
|
||||
=> await HandleDeletionAsync(id, media => ContentService.Delete(media, userId).Result, true);
|
||||
|
||||
protected override IMedia Create(string? name, int parentId, IMediaType contentType)
|
||||
=> new Models.Media(name, parentId, contentType);
|
||||
|
||||
private ContentEditingOperationStatus Save(IMedia media, int userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Attempt<OperationResult?> saveResult = ContentService.Save(media, userId);
|
||||
return saveResult.Result?.Result switch
|
||||
{
|
||||
// these are the only result states currently expected from Save
|
||||
OperationResultType.Success => ContentEditingOperationStatus.Success,
|
||||
OperationResultType.FailedCancelledByEvent => ContentEditingOperationStatus.CancelledByNotification,
|
||||
|
||||
// for any other state we'll return "unknown" so we know that we need to amend this
|
||||
_ => ContentEditingOperationStatus.Unknown
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Media save operation failed");
|
||||
return ContentEditingOperationStatus.Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,5 +12,6 @@ public enum ContentEditingOperationStatus
|
||||
TemplateNotFound,
|
||||
TemplateNotAllowed,
|
||||
PropertyTypeNotFound,
|
||||
InTrash,
|
||||
Unknown
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user