V14: allowed children endpoints (#14434)
* Implement allowed children of root * Allow children by key controller * Update to be document controlller instead * Fix AllowedChildrenOfRootDocumentController * Create GetAllAsync method in ContentTypeServiceBaseOfTRepositoryTItemTService * Revert "Create GetAllAsync method in ContentTypeServiceBaseOfTRepositoryTItemTService" This reverts commit b01b5b924099e58bb53246e4b4ba5fa15358d0cd. * Implement attemp pattern in IContentTypeService * Create IContentCreatingService * Use new contentCreatingService in controller * Revert if statement * Use total from attempt * Throw exceptions instead of returning attempt * Wrap in scope * Rename to GetAllowedChildrenContentTypesAsync * Fix summary * Removed unneccessary await Task.FromResult --------- Co-authored-by: Zeegaan <nge@umbraco.dk> Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -43,4 +43,11 @@ public class ContentControllerBase : ManagementApiControllerBase
|
||||
ContentEditingOperationStatus.Unknown => StatusCode(StatusCodes.Status500InternalServerError, "Unknown error. Please see the log for more details."),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown content operation status.")
|
||||
};
|
||||
|
||||
protected IActionResult ContentCreatingOperationStatusResult(ContentCreatingOperationStatus status) =>
|
||||
status switch
|
||||
{
|
||||
ContentCreatingOperationStatus.NotFound => NotFound("The content type could not be found"),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown content operation status."),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Document;
|
||||
|
||||
public class AllowedChildrenByKeyDocumentController : DocumentControllerBase
|
||||
{
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
private readonly IContentCreatingService _contentCreatingService;
|
||||
|
||||
public AllowedChildrenByKeyDocumentController(IUmbracoMapper umbracoMapper, IContentCreatingService contentCreatingService)
|
||||
{
|
||||
_umbracoMapper = umbracoMapper;
|
||||
_contentCreatingService = contentCreatingService;
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}/allowed-document-types")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<DocumentTypeResponseModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> AllowedChildrenByKey(Guid id, int skip = 0, int take = 100)
|
||||
{
|
||||
Attempt<PagedModel<IContentType>?, ContentCreatingOperationStatus> allowedChildrenAttempt = await _contentCreatingService.GetAllowedChildrenContentTypesAsync(id, skip, take);
|
||||
|
||||
if (allowedChildrenAttempt.Success is false)
|
||||
{
|
||||
return ContentCreatingOperationStatusResult(allowedChildrenAttempt.Status);
|
||||
}
|
||||
|
||||
List<DocumentTypeResponseModel> viewModels = _umbracoMapper.MapEnumerable<IContentType, DocumentTypeResponseModel>(allowedChildrenAttempt.Result!.Items);
|
||||
|
||||
var pagedViewModel = new PagedViewModel<DocumentTypeResponseModel>
|
||||
{
|
||||
Total = allowedChildrenAttempt.Result.Total,
|
||||
Items = viewModels,
|
||||
};
|
||||
|
||||
return Ok(pagedViewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Document;
|
||||
|
||||
public class AllowedChildrenOfRootDocumentController : DocumentControllerBase
|
||||
{
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public AllowedChildrenOfRootDocumentController(IContentTypeService contentTypeService, IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_contentTypeService = contentTypeService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
[HttpGet("root/allowed-document-types")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<DocumentTypeResponseModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> AllowedChildrenOfRoot(int skip = 0, int take = 100)
|
||||
{
|
||||
PagedModel<IContentType> allowedChildrenOfRoot = await _contentTypeService.GetAllAllowedAsRootAsync(skip, take);
|
||||
|
||||
List<DocumentTypeResponseModel> viewModels = _umbracoMapper.MapEnumerable<IContentType, DocumentTypeResponseModel>(allowedChildrenOfRoot.Items);
|
||||
|
||||
var pagedViewModel = new PagedViewModel<DocumentTypeResponseModel>
|
||||
{
|
||||
Total = allowedChildrenOfRoot.Total,
|
||||
Items = viewModels,
|
||||
};
|
||||
|
||||
return await Task.FromResult(Ok(pagedViewModel));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Content;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
|
||||
@@ -298,6 +298,7 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
Services.AddUnique<ITagService, TagService>();
|
||||
Services.AddUnique<IContentService, ContentService>();
|
||||
Services.AddUnique<IContentEditingService, ContentEditingService>();
|
||||
Services.AddUnique<IContentCreatingService, ContentCreatingService>();
|
||||
Services.AddUnique<IContentVersionCleanupPolicy, DefaultContentVersionCleanupPolicy>();
|
||||
Services.AddUnique<IMemberService, MemberService>();
|
||||
Services.AddUnique<IMediaService, MediaService>();
|
||||
|
||||
52
src/Umbraco.Core/Services/ContentCreatingService.cs
Normal file
52
src/Umbraco.Core/Services/ContentCreatingService.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
public class ContentCreatingService : IContentCreatingService
|
||||
{
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly ICoreScopeProvider _coreScopeProvider;
|
||||
|
||||
public ContentCreatingService(IContentTypeService contentTypeService, IContentService contentService, IEntityService entityService, ICoreScopeProvider coreScopeProvider)
|
||||
{
|
||||
_contentTypeService = contentTypeService;
|
||||
_contentService = contentService;
|
||||
_entityService = entityService;
|
||||
_coreScopeProvider = coreScopeProvider;
|
||||
}
|
||||
|
||||
public async Task<Attempt<PagedModel<IContentType>?, ContentCreatingOperationStatus>> GetAllowedChildrenContentTypesAsync(Guid key, int skip, int take)
|
||||
{
|
||||
using ICoreScope scope = _coreScopeProvider.CreateCoreScope();
|
||||
IContent? content = _contentService.GetById(key);
|
||||
|
||||
if (content is null)
|
||||
{
|
||||
return Attempt.FailWithStatus<PagedModel<IContentType>?, ContentCreatingOperationStatus>(ContentCreatingOperationStatus.NotFound, null);
|
||||
}
|
||||
|
||||
// FIXME: When content gets a ContentTypeKey property, we no longer have to get the key from the entityService
|
||||
Attempt<Guid> contentTypeKeyAttempt = _entityService.GetKey(content.ContentTypeId, UmbracoObjectTypes.DocumentType);
|
||||
|
||||
if (contentTypeKeyAttempt.Success is false)
|
||||
{
|
||||
// This should never happen, content shouldn't be able to exists without a document type
|
||||
throw new InvalidOperationException("The document type could not be found.");
|
||||
}
|
||||
|
||||
Attempt<PagedModel<IContentType>?, ContentTypeOperationStatus> contentTypeAttempt = await _contentTypeService.GetAllowedChildrenAsync(contentTypeKeyAttempt.Result, skip, take);
|
||||
|
||||
if (contentTypeAttempt.Success is false)
|
||||
{
|
||||
throw new InvalidOperationException("The document type could not be found.");
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
|
||||
return Attempt.SucceedWithStatus(ContentCreatingOperationStatus.Success, contentTypeAttempt.Result);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,11 @@ using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Persistence.Querying;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.Changes;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -82,6 +84,47 @@ public class ContentTypeService : ContentTypeServiceBase<IContentTypeRepository,
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<PagedModel<IContentType>> GetAllAllowedAsRootAsync(int skip, int take)
|
||||
{
|
||||
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
|
||||
|
||||
// that one is special because it works across content, media and member types
|
||||
scope.ReadLock(Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes);
|
||||
|
||||
IQuery<IContentType> query = ScopeProvider.CreateQuery<IContentType>().Where(x => x.AllowedAsRoot);
|
||||
IEnumerable<IContentType> contentTypes = Repository.Get(query).ToArray();
|
||||
|
||||
var pagedModel = new PagedModel<IContentType>
|
||||
{
|
||||
Total = contentTypes.Count(),
|
||||
Items = contentTypes.Skip(skip).Take(take)
|
||||
};
|
||||
|
||||
return Task.FromResult(pagedModel);
|
||||
}
|
||||
|
||||
public Task<Attempt<PagedModel<IContentType>?, ContentTypeOperationStatus>> GetAllowedChildrenAsync(Guid key, int skip, int take)
|
||||
{
|
||||
using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true);
|
||||
IContentType? parent = Get(key);
|
||||
|
||||
if (parent?.AllowedContentTypes is null)
|
||||
{
|
||||
return Task.FromResult(Attempt.FailWithStatus<PagedModel<IContentType>?, ContentTypeOperationStatus>(ContentTypeOperationStatus.NotFound, null));
|
||||
}
|
||||
|
||||
IContentType[] allowedChildren = GetAll(parent.AllowedContentTypes.Select(x => x.Key)).ToArray();
|
||||
|
||||
var result = new PagedModel<IContentType>
|
||||
{
|
||||
Items = allowedChildren.Take(take).Skip(skip),
|
||||
Total = allowedChildren.Length,
|
||||
};
|
||||
|
||||
return Task.FromResult(Attempt.SucceedWithStatus<PagedModel<IContentType>?, ContentTypeOperationStatus>(ContentTypeOperationStatus.Success, result));
|
||||
}
|
||||
|
||||
protected override void DeleteItemsOfTypes(IEnumerable<int> typeIds)
|
||||
{
|
||||
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
|
||||
|
||||
9
src/Umbraco.Core/Services/IContentCreatingService.cs
Normal file
9
src/Umbraco.Core/Services/IContentCreatingService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
public interface IContentCreatingService
|
||||
{
|
||||
Task<Attempt<PagedModel<IContentType>?, ContentCreatingOperationStatus>> GetAllowedChildrenContentTypesAsync(Guid key, int skip, int take);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -29,4 +30,16 @@ public interface IContentTypeService : IContentTypeBaseService<IContentType>
|
||||
/// <param name="aliases"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<int> GetAllContentTypeIds(string[] aliases);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the content type allowed as root.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<PagedModel<IContentType>> GetAllAllowedAsRootAsync(int skip, int take);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all content types allowed as children for a given content type key.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<Attempt<PagedModel<IContentType>?, ContentTypeOperationStatus>> GetAllowedChildrenAsync(Guid key, int skip, int take);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum ContentCreatingOperationStatus
|
||||
{
|
||||
Success,
|
||||
NotFound
|
||||
}
|
||||
@@ -6,5 +6,6 @@ public enum ContentTypeOperationStatus
|
||||
DuplicateAlias,
|
||||
InvalidAlias,
|
||||
InvalidPropertyTypeAlias,
|
||||
InvalidDataType
|
||||
InvalidDataType,
|
||||
NotFound
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user