Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public async Task<ActionResult> Item(
CancellationToken cancellationToken,
[FromQuery(Name = "id")] HashSet<Guid> ids)
{
if (ids.Count is 0)
{
return Ok(Enumerable.Empty<DocumentBlueprintItemResponseModel>());
}

IEnumerable<IDocumentEntitySlim> documents = _entityService
.GetAll(UmbracoObjectTypes.DocumentBlueprint, ids.ToArray())
.Select(x => x as IDocumentEntitySlim)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Tree;
using Umbraco.Cms.Core.Services;

namespace Umbraco.Cms.Api.Management.Controllers.DocumentBlueprint.Tree;

[ApiVersion("1.0")]
public class AncestorsDocumentBlueprintTreeController : DocumentBlueprintTreeControllerBase
{
public AncestorsDocumentBlueprintTreeController(IEntityService entityService, IDocumentPresentationFactory documentPresentationFactory)
: base(entityService, documentPresentationFactory)
{
}

[HttpGet("ancestors")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(IEnumerable<DocumentBlueprintTreeItemResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<IEnumerable<DocumentBlueprintTreeItemResponseModel>>> Ancestors(CancellationToken cancellationToken, Guid descendantId)
=> await GetAncestors(descendantId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
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;
using Umbraco.Cms.Web.Common.Authorization;

namespace Umbraco.Cms.Api.Management.Controllers.DocumentType;

[ApiVersion("1.0")]
[Authorize(Policy = AuthorizationPolicies.SectionAccessContent)]
public class DocumentBlueprintForDocumentTypeController : DocumentTypeControllerBase
{
private readonly IContentBlueprintEditingService _contentBlueprintEditingService;

private readonly IUmbracoMapper _umbracoMapper;

public DocumentBlueprintForDocumentTypeController(IContentBlueprintEditingService contentBlueprintEditingService, IUmbracoMapper umbracoMapper)
{
_contentBlueprintEditingService = contentBlueprintEditingService;
_umbracoMapper = umbracoMapper;
}

[HttpGet("{id:guid}/blueprint")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<DocumentTypeBlueprintItemResponseModel>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> DocumentBlueprintByDocumentTypeKey(
CancellationToken cancellationToken,
Guid id,
int skip = 0,
int take = 100)
{
Attempt<PagedModel<IContent>?, ContentEditingOperationStatus> attempt = await _contentBlueprintEditingService.GetPagedByContentTypeAsync(id, skip, take);
if (attempt.Success is false)
{
return ContentEditingOperationStatusResult(attempt.Status);
}

List<DocumentTypeBlueprintItemResponseModel> viewModels = _umbracoMapper.MapEnumerable<IContent, DocumentTypeBlueprintItemResponseModel>(attempt.Result!.Items);

var pagedViewModel = new PagedViewModel<DocumentTypeBlueprintItemResponseModel>
{
Total = attempt.Result!.Total,
Items = viewModels,
};

return Ok(pagedViewModel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,15 @@ status is ContentTypeStructureOperationStatus.Success
.Build()),
_ => new ObjectResult("Unknown content type structure operation status") { StatusCode = StatusCodes.Status500InternalServerError }
});

protected IActionResult ContentEditingOperationStatusResult(ContentEditingOperationStatus status) =>
OperationStatusResult(status, problemDetailsBuilder => status switch
{
ContentEditingOperationStatus.ContentTypeNotFound => NotFound(problemDetailsBuilder
.WithTitle("The specified document type was not found")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, problemDetailsBuilder
.WithTitle("Unknown content editing operation status")
.Build()),
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public void DefineMaps(IUmbracoMapper mapper)
mapper.Define<ISimpleContentType, DocumentTypeCollectionReferenceResponseModel>((_, _) => new DocumentTypeCollectionReferenceResponseModel(), Map);
mapper.Define<IContentEntitySlim, DocumentTypeReferenceResponseModel>((_, _) => new DocumentTypeReferenceResponseModel(), Map);
mapper.Define<IDocumentEntitySlim, DocumentTypeReferenceResponseModel>((_, _) => new DocumentTypeReferenceResponseModel(), Map);
mapper.Define<IContent, DocumentTypeBlueprintItemResponseModel>((_, _) => new DocumentTypeBlueprintItemResponseModel(), Map);
}

// Umbraco.Code.MapAll
Expand Down Expand Up @@ -114,4 +115,11 @@ private void Map(ISimpleContentType source, DocumentTypeCollectionReferenceRespo
target.Alias = source.Alias;
target.Icon = source.Icon ?? string.Empty;
}

// Umbraco.Code.MapAll
private void Map(IContent source, DocumentTypeBlueprintItemResponseModel target, MapperContext context)
{
target.Id = source.Key;
target.Name = source.Name ?? string.Empty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.Item;

namespace Umbraco.Cms.Api.Management.ViewModels.DocumentType;

public class DocumentTypeBlueprintItemResponseModel : NamedItemResponseModelBase
{
}
19 changes: 19 additions & 0 deletions src/Umbraco.Core/Services/ContentBlueprintEditingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@ public ContentBlueprintEditingService(
return await Task.FromResult(blueprint);
}

public async Task<Attempt<PagedModel<IContent>?, ContentEditingOperationStatus>> GetPagedByContentTypeAsync(Guid contentTypeKey, int skip, int take)
{
IContentType? contentType = await ContentTypeService.GetAsync(contentTypeKey);
if (contentType is null)
{
return Attempt.FailWithStatus<PagedModel<IContent>?, ContentEditingOperationStatus>(ContentEditingOperationStatus.ContentTypeNotFound, null);
}

IContent[] blueprints = ContentService.GetBlueprintsForContentTypes([contentType.Id]).ToArray();

var result = new PagedModel<IContent>
{
Items = blueprints.Skip(skip).Take(take),
Total = blueprints.Length,
};

return Attempt.SucceedWithStatus<PagedModel<IContent>?, ContentEditingOperationStatus>(ContentEditingOperationStatus.Success, result);
}

public async Task<Attempt<ContentCreateResult, ContentEditingOperationStatus>> CreateAsync(ContentBlueprintCreateModel createModel, Guid userKey)
{
if (await ValidateCulturesAsync(createModel) is false)
Expand Down
5 changes: 5 additions & 0 deletions src/Umbraco.Core/Services/IContentBlueprintEditingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ public interface IContentBlueprintEditingService
{
Task<IContent?> GetAsync(Guid key);

Task<Attempt<PagedModel<IContent>?, ContentEditingOperationStatus>> GetPagedByContentTypeAsync(
Guid contentTypeKey,
int skip,
int take);

Task<Attempt<ContentCreateResult, ContentEditingOperationStatus>> CreateAsync(ContentBlueprintCreateModel createModel, Guid userKey);

Task<Attempt<ContentCreateResult, ContentEditingOperationStatus>> CreateFromContentAsync(Guid contentKey, string name, Guid? key, Guid userKey);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
public partial class ContentBlueprintEditingServiceTests
{
[TestCase(true)]
[TestCase(true)]
[TestCase(false)]
public async Task Can_Get(bool variant)
{
var blueprint = await (variant ? CreateVariantContentBlueprint() : CreateInvariantContentBlueprint());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Services.OperationStatus;

namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;

public partial class ContentBlueprintEditingServiceTests
{
[Test]
public async Task Can_Get_Paged()
{
var contentType = CreateInvariantContentType();

for (var i = 1; i < 6; i++)
{
var createModel = new ContentBlueprintCreateModel
{
ContentTypeKey = contentType.Key,
InvariantName = $"Blueprint {i}",
};

await ContentBlueprintEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
}

var result = await ContentBlueprintEditingService.GetPagedByContentTypeAsync(contentType.Key, 0, 2);

var pagedResult = result.Result;
Assert.Multiple(() =>
{
Assert.IsTrue(result.Success);
Assert.AreEqual(ContentEditingOperationStatus.Success, result.Status);
Assert.IsNotNull(pagedResult);
});
Assert.Multiple(() =>
{
Assert.AreEqual(2, pagedResult.Items.Count());
Assert.AreEqual(5, pagedResult.Total);
});
}

[Test]
public async Task Cannot_Get_Paged_With_Non_Existing_Content_Type()
{
var result = await ContentBlueprintEditingService.GetPagedByContentTypeAsync(Guid.NewGuid(), 0, 10);

Assert.Multiple(() =>
{
Assert.IsFalse(result.Success);
Assert.AreEqual(ContentEditingOperationStatus.ContentTypeNotFound, result.Status);
Assert.IsNull(result.Result);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
public partial class ContentEditingServiceTests
{
[TestCase(true)]
[TestCase(true)]
[TestCase(false)]
public async Task Can_Get(bool variant)
{
var content = await (variant ? CreateVariantContent() : CreateInvariantContent());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@
<Compile Update="Umbraco.Infrastructure\Services\ContentBlueprintEditingServiceTests.Get.cs">
<DependentUpon>ContentBlueprintEditingServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Infrastructure\Services\ContentBlueprintEditingServiceTests.GetPagedByContentTypeKey.cs">
<DependentUpon>ContentBlueprintEditingServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Infrastructure\Services\ContentBlueprintEditingServiceTests.Move.cs">
<DependentUpon>ContentBlueprintEditingServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Infrastructure\Services\ContentBlueprintEditingServiceTests.Update.cs">
<DependentUpon>ContentBlueprintEditingServiceTests.cs</DependentUpon>
</Compile>
Expand Down