Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
148ac51
CRUD + folders + API
kjac Jul 25, 2025
b25ee76
Merge branch 'main' into v16/temp/element-poc
kjac Aug 11, 2025
eea3c57
Fix infinite recursion
kjac Aug 11, 2025
d2e0416
Distributed cache handling for Elements
kjac Aug 13, 2025
70b5c52
Publishing for Elements (incl. refactor)
kjac Aug 13, 2025
251b8a4
Fix bad file name
kjac Aug 13, 2025
fd59a8b
Added "foldersOnly" option to the siblings endpoint
kjac Aug 13, 2025
eadd6ec
Update src/Umbraco.Core/Models/UmbracoObjectTypes.cs
kjac Aug 13, 2025
523d96a
Merge branch 'main' into v16/temp/element-poc
kjac Aug 14, 2025
d6b5d57
API for publishing elements
kjac Aug 14, 2025
632b89d
Published element cache (WIP)
kjac Aug 14, 2025
ca9f0bd
Fix delete at repo level
kjac Aug 15, 2025
feb07a2
Fixing up a little tests
kjac Aug 15, 2025
3a53a9b
Element picker property editor
kjac Aug 15, 2025
d7b4fad
Added tests to prove published element status
kjac Aug 15, 2025
2ce2b51
Merge branch 'main' into v16/temp/element-poc
kjac Sep 1, 2025
28abcf3
Move scheduled content keys to base abstraction
kjac Sep 1, 2025
0a2a518
Add request caching for published element creation (similar to publis…
kjac Sep 1, 2025
264f4c1
Merge branch 'main' into v16/temp/element-poc
kjac Sep 5, 2025
e7ae4ab
Apply conditional appcache access to elements as well
kjac Sep 5, 2025
26ed5fb
Fix test build errors
kjac Sep 5, 2025
064c7bd
Merge branch 'main' into v16/temp/element-poc
kjac Sep 10, 2025
1644b0e
Fix merge from main
kjac Sep 10, 2025
0e9c45f
Merge branch 'main' into v16/temp/element-poc
kjac Oct 2, 2025
9962072
Fix merge
kjac Oct 2, 2025
5fd8f54
Merge branch 'main' into v16/temp/element-poc
kjac Oct 16, 2025
8defac5
Merge branch 'main' into v16/temp/element-poc
kjac Oct 16, 2025
908b4de
Add cache invalidation on update (like content and media)
kjac Oct 24, 2025
6359d45
Move element (incl. tests)
kjac Oct 24, 2025
f0031a7
Element copying
kjac Oct 31, 2025
922fbc8
Add items endpoint incl. variation info at item level
kjac Nov 3, 2025
8bc3b8b
Make the Element tree items look like Document tree items (with varia…
kjac Nov 19, 2025
a566528
Rename all things ElementType to DocumentType
kjac Nov 20, 2025
058798c
Move ElementRepository to the right place
kjac Nov 20, 2025
abdc2f0
Merge branch 'main' into v16/temp/element-poc
kjac Nov 20, 2025
9146adf
Fix auditing after merge (changes from #19357)
kjac Nov 24, 2025
47443fa
Fix dates after merge (changes from #19822)
kjac Nov 24, 2025
1c6ff8b
Fix NPoco querying after merge (changes from #20184)
kjac Nov 24, 2025
6f0b217
Fix various build errors after merge
kjac Nov 24, 2025
9af0d1b
Merge branch 'main' into v17/feature/global-elements
kjac Nov 24, 2025
87fadc9
Merge branch 'main' into v17/feature/global-elements
kjac Dec 5, 2025
1fa9fd5
Move containers
kjac Dec 9, 2025
b019c31
Merge branch 'main' into v17/feature/global-elements
kjac Dec 9, 2025
9ff9103
Add migration to create element tables
kjac Dec 9, 2025
223d0d9
Merge branch 'main' into v17/feature/global-elements
kjac Dec 17, 2025
6396c1f
Re-implement #21105 at base class level
kjac Dec 17, 2025
b33297e
Merge branch 'main' into v17/feature/global-elements
kjac Dec 29, 2025
c9130eb
Fix merge
kjac Dec 29, 2025
ea5a797
Add element tree recycle bin + move element to/from recycle bin
kjac Dec 30, 2025
f1d02c6
Controllers for move to recycle bin + recycle bin root
kjac Jan 2, 2026
b355e1e
Support element containers in recycle bin (no controllers)
kjac Jan 2, 2026
b3c14d6
Handle error cases for element moves and add more tests
kjac Jan 3, 2026
cf2433b
Do not allow creation of IPublishedElement for trashed elements
kjac Jan 4, 2026
42e86df
Amend recycle bin controller output and add children controller
kjac Jan 4, 2026
59e93e5
Merge branch 'main' into v17/feature/global-elements
kjac Jan 5, 2026
97782a1
Regenerate OpenApi.json with Element APIs
kjac Jan 5, 2026
ab50f7e
Housekeeping: Organize element container service tests
kjac Jan 5, 2026
e1b648e
Fix bad housekeeping
kjac Jan 5, 2026
4b2a3f3
Add missing siblings controller for recycle bin
kjac Jan 5, 2026
352dbc0
Add "delete from recycle bin" and "empty recycle bin" operations (inc…
kjac Jan 5, 2026
9e28241
Updated OpenApi.json to reflect new endpoints
kjac Jan 5, 2026
d21746a
Added `CreateDate` to `ElementTreeItemResponseModel`
leekelleher Jan 7, 2026
30f2f46
Re-generated OpenAPI.json
leekelleher Jan 7, 2026
7659b46
Add configuration endpoint for Elements
kjac Jan 7, 2026
453da71
Explicitly unpublish published elements when restoring from recycle bin.
kjac Jan 8, 2026
3d00fee
Merge branch 'main' into v17/feature/global-elements
kjac Jan 12, 2026
bf0fd20
Merge branch 'v18/dev' into v17/feature/global-elements
lauraneto Jan 13, 2026
1ee7f0e
Elements: Remove invalid templateId from ElementVersionDto index defi…
lauraneto Jan 14, 2026
cc1dd48
Fix the ordering of items in the tree
kjac Jan 14, 2026
ec87d88
It's 2026 now...
kjac Jan 14, 2026
6f92c61
Fix missing project structure
kjac Jan 14, 2026
2088567
Amend empty recycle bin
kjac Jan 14, 2026
f0cb616
Elements: Fix element recycle bin node insertion on SQL Server (#21390)
lauraneto Jan 14, 2026
a3ff86f
Fix count trashed children
kjac Jan 15, 2026
fd3b1ac
Moved newly added entity service tests to an isolated, per-test DB cl…
kjac Jan 15, 2026
e3fef11
Elements: Element start node permissions (#21375)
lauraneto Jan 15, 2026
98b9359
Elements: Add rollback (#21393)
kjac Jan 15, 2026
b8f4bbe
Elements: Regenerate OpenApi.json
lauraneto Jan 15, 2026
d6cb11f
Elements: Add default and granular permissions for Element controller…
lauraneto Jan 16, 2026
577f351
Merge branch 'v18/dev' into v17/feature/global-elements
kjac Jan 16, 2026
2a58892
Add element folder "item" endpoint
kjac Jan 19, 2026
79e3965
Include "isTrashed" in folder response models
kjac Jan 19, 2026
4852c93
Update TODOs
kjac Jan 20, 2026
095af03
Rollback a few unnecessarily breaking signature changes
kjac Jan 20, 2026
59f838a
Merge remote-tracking branch 'origin/v18/dev' into v17/feature/global…
kjac Jan 21, 2026
f522d04
Use schema constants from #21327
kjac Jan 21, 2026
e6f7c88
Elements: Add admin group element permissions during upgrade (#21452)
lauraneto Jan 21, 2026
94bf319
Elements: Fix Writer expected status codes in Element controller perm…
lauraneto Jan 22, 2026
d91a829
Elements: Fix duplicate column name in DocumentVersionDto index defin…
lauraneto Jan 22, 2026
7e01fc0
Add missing element mapper and allow deleting element types with acti…
kjac Jan 22, 2026
c85d9d7
Update src/Umbraco.Core/Cache/Refreshers/Implement/ElementCacheRefres…
kjac Jan 22, 2026
5dab68b
Review comment: ReadOnlyUserGroup constructor
kjac Jan 22, 2026
0d907b0
Merge remote-tracking branch 'origin/v17/feature/global-elements' int…
kjac Jan 22, 2026
625e814
Update comments in ElementEditingService
kjac Jan 22, 2026
085602e
Add Library section access to content, media, and member tree policies
lauraneto Jan 23, 2026
58252f6
Elements: Add Elements access to data type, document type, and relati…
lauraneto Jan 23, 2026
90c2c6d
Merge branch 'v18/dev' into v17/feature/global-elements
kjac Jan 23, 2026
886ff16
Merge branch 'v18/dev' into v17/feature/global-elements
kjac Jan 27, 2026
204ce53
Amend merge from v18/dev
kjac Jan 27, 2026
b63020e
Merge branch 'v18/dev' into v17/feature/global-elements
lauraneto Jan 28, 2026
416f544
Global Elements: Backoffice UI implementation (#21410)
leekelleher Feb 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.DataType;

[VersionedApiBackOfficeRoute(Constants.UdiEntityType.DataType)]
[ApiExplorerSettings(GroupName = "Data Type")]
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentsOrMediaOrMembersOrContentTypes)]
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentsOrElementsOrMediaOrMembersOrContentTypes)]
public abstract class DataTypeControllerBase : ManagementApiControllerBase
{
protected IActionResult DataTypeOperationStatusResult(DataTypeOperationStatus status) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ protected IActionResult DocumentEditingOperationStatusResult<TContentModelBase>(
where TContentModelBase : ContentModelBase<DocumentValueModel, DocumentVariantRequestModel>
=> ContentEditingOperationStatusResult<TContentModelBase, DocumentValueModel, DocumentVariantRequestModel>(status, requestModel, validationResult);

// TODO ELEMENTS: move this to ContentControllerBase
protected IActionResult DocumentPublishingOperationStatusResult(
ContentPublishingOperationStatus status,
IEnumerable<string>? invalidPropertyAliases = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Api.Management.Controllers.DocumentType;

[VersionedApiBackOfficeRoute(Constants.UdiEntityType.DocumentType)]
[ApiExplorerSettings(GroupName = "Document Type")]
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentsOrDocumentTypes)]
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentsOrElementsOrDocumentTypes)]
public abstract class DocumentTypeControllerBase : ManagementApiControllerBase
{
protected IActionResult OperationStatusResult(ContentTypeOperationStatus status)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,17 @@ public async Task<IActionResult> All(
Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus> attempt =
await _contentVersionService.GetPagedContentVersionsAsync(documentId, culture, skip, take);

if (attempt.Success is false)
{
return MapFailure(attempt.Status);
}

var pagedViewModel = new PagedViewModel<DocumentVersionItemResponseModel>
{
Total = attempt.Result!.Total,
Items = await _documentVersionPresentationFactory.CreateMultipleAsync(attempt.Result!.Items),
};

return attempt.Success
? Ok(pagedViewModel)
: MapFailure(attempt.Status);
return Ok(pagedViewModel);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,26 @@ namespace Umbraco.Cms.Api.Management.Controllers.DocumentVersion;
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocuments)]
public abstract class DocumentVersionControllerBase : ManagementApiControllerBase
{
protected IActionResult MapFailure(ContentVersionOperationStatus status)
internal static IActionResult MapFailure(ContentVersionOperationStatus status)
=> OperationStatusResult(status, problemDetailsBuilder => status switch
{
ContentVersionOperationStatus.NotFound => NotFound(problemDetailsBuilder
ContentVersionOperationStatus.NotFound => new NotFoundObjectResult(problemDetailsBuilder
.WithTitle("The requested version could not be found")
.Build()),
ContentVersionOperationStatus.ContentNotFound => NotFound(problemDetailsBuilder
ContentVersionOperationStatus.ContentNotFound => new NotFoundObjectResult(problemDetailsBuilder
.WithTitle("The requested document could not be found")
.Build()),
ContentVersionOperationStatus.InvalidSkipTake => SkipTakeToPagingProblem(),
ContentVersionOperationStatus.RollBackFailed => BadRequest(problemDetailsBuilder
ContentVersionOperationStatus.RollBackFailed => new BadRequestObjectResult(problemDetailsBuilder
.WithTitle("Rollback failed")
.WithDetail("An unspecified error occurred while rolling back the requested version. Please check the logs for additional information.")),
ContentVersionOperationStatus.RollBackCanceled => BadRequest(problemDetailsBuilder
.WithDetail(
"An unspecified error occurred while rolling back the requested version. Please check the logs for additional information.")),
ContentVersionOperationStatus.RollBackCanceled => new BadRequestObjectResult(problemDetailsBuilder
.WithTitle("Request cancelled by notification")
.WithDetail("The request to roll back was cancelled by a notification handler.")
.Build()),
_ => StatusCode(StatusCodes.Status500InternalServerError, problemDetailsBuilder
_ => new ObjectResult(problemDetailsBuilder
.WithTitle("Unknown content version operation status.")
.Build()),
.Build()) { StatusCode = StatusCodes.Status500InternalServerError },
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Element;
using Umbraco.Cms.Core.Actions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Web.Common.Authorization;
using Umbraco.Extensions;

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

[ApiVersion("1.0")]
public class ByKeyElementController : ElementControllerBase
{
private readonly IAuthorizationService _authorizationService;
private readonly IElementService _elementService;
private readonly IElementPresentationFactory _elementPresentationFactory;

public ByKeyElementController(
IAuthorizationService authorizationService,
IElementService elementService,
IElementPresentationFactory elementPresentationFactory)
{
_authorizationService = authorizationService;
_elementService = elementService;
_elementPresentationFactory = elementPresentationFactory;
}

[HttpGet("{id:guid}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ElementResponseModel), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> ByKey(CancellationToken cancellationToken, Guid id)
{
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
User,
ElementPermissionResource.WithKeys(ActionElementBrowse.ActionLetter, id),
AuthorizationPolicies.ElementPermissionByResource);

if (!authorizationResult.Succeeded)
{
return Forbidden();
}

IElement? element = _elementService.GetById(id);
if (element is null)
{
return ContentEditingOperationStatusResult(ContentEditingOperationStatus.NotFound);
}

ContentScheduleCollection contentScheduleCollection = _elementService.GetContentScheduleByContentId(id);

ElementResponseModel model = _elementPresentationFactory.CreateResponseModel(element, contentScheduleCollection);
return Ok(model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Element;

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

[ApiVersion("1.0")]
public class ConfigurationElementController : ElementControllerBase
{
private readonly IConfigurationPresentationFactory _configurationPresentationFactory;

public ConfigurationElementController(IConfigurationPresentationFactory configurationPresentationFactory)
=> _configurationPresentationFactory = configurationPresentationFactory;

[HttpGet("configuration")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(ElementConfigurationResponseModel), StatusCodes.Status200OK)]
public Task<IActionResult> Configuration(CancellationToken cancellationToken)
{
ElementConfigurationResponseModel responseModel = _configurationPresentationFactory.CreateElementConfigurationResponseModel();
return Task.FromResult<IActionResult>(Ok(responseModel));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Element;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Actions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Web.Common.Authorization;
using Umbraco.Extensions;

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

[ApiVersion("1.0")]
public class CopyElementController : ElementControllerBase
{
private readonly IAuthorizationService _authorizationService;
private readonly IElementEditingService _elementEditingService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;

public CopyElementController(
IAuthorizationService authorizationService,
IElementEditingService elementEditingService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_authorizationService = authorizationService;
_elementEditingService = elementEditingService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}

[HttpPost("{id:guid}/copy")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Copy(CancellationToken cancellationToken, Guid id, CopyElementRequestModel copyElementRequestModel)
{
// Check Copy permission on source element
AuthorizationResult sourceAuthorizationResult = await _authorizationService.AuthorizeResourceAsync(
User,
ElementPermissionResource.WithKeys(ActionElementCopy.ActionLetter, id),
AuthorizationPolicies.ElementPermissionByResource);

if (!sourceAuthorizationResult.Succeeded)
{
return Forbidden();
}

// Check Create permission on target (where we're copying to)
AuthorizationResult targetAuthorizationResult = await _authorizationService.AuthorizeResourceAsync(
User,
ElementPermissionResource.WithKeys(ActionElementNew.ActionLetter, copyElementRequestModel.Target?.Id),
AuthorizationPolicies.ElementPermissionByResource);

if (!targetAuthorizationResult.Succeeded)
{
return Forbidden();
}

Attempt<IElement?, ContentEditingOperationStatus> result = await _elementEditingService.CopyAsync(
id,
copyElementRequestModel.Target?.Id,
CurrentUserKey(_backOfficeSecurityAccessor));

return result.Success
? CreatedAtId<ByKeyElementController>(controller => nameof(controller.ByKey), result.Result!.Key)
: ContentEditingOperationStatusResult(result.Status);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.Element;
using Umbraco.Cms.Core;
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.Element;

[ApiVersion("1.0")]
public class CreateElementController : CreateElementControllerBase
{
private readonly IElementEditingPresentationFactory _elementEditingPresentationFactory;
private readonly IElementEditingService _elementEditingService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;

public CreateElementController(
IAuthorizationService authorizationService,
IElementEditingPresentationFactory elementEditingPresentationFactory,
IElementEditingService elementEditingService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
: base(authorizationService)
{
_elementEditingPresentationFactory = elementEditingPresentationFactory;
_elementEditingService = elementEditingService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}

[HttpPost]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Create(CancellationToken cancellationToken, CreateElementRequestModel requestModel)
=> await HandleRequest(requestModel, async () =>
{
ElementCreateModel model = _elementEditingPresentationFactory.MapCreateModel(requestModel);
Attempt<ElementCreateResult, ContentEditingOperationStatus> result =
await _elementEditingService.CreateAsync(model, CurrentUserKey(_backOfficeSecurityAccessor));

return result.Success
? CreatedAtId<ByKeyElementController>(controller => nameof(controller.ByKey), result.Result.Content!.Key)
: ContentEditingOperationStatusResult(result.Status);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.ViewModels.Element;
using Umbraco.Cms.Core.Actions;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Web.Common.Authorization;
using Umbraco.Extensions;

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

public abstract class CreateElementControllerBase : ElementControllerBase
{
private readonly IAuthorizationService _authorizationService;

protected CreateElementControllerBase(IAuthorizationService authorizationService)
=> _authorizationService = authorizationService;

protected async Task<IActionResult> HandleRequest(CreateElementRequestModel requestModel, Func<Task<IActionResult>> authorizedHandler)
{
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
User,
ElementPermissionResource.WithKeys(ActionElementNew.ActionLetter, requestModel.Parent?.Id),
AuthorizationPolicies.ElementPermissionByResource);

if (authorizationResult.Succeeded is false)
{
return Forbidden();
}

return await authorizedHandler();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Actions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Web.Common.Authorization;
using Umbraco.Extensions;

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

[ApiVersion("1.0")]
public class DeleteElementController : ElementControllerBase
{
private readonly IAuthorizationService _authorizationService;
private readonly IElementEditingService _elementEditingService;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;

public DeleteElementController(
IAuthorizationService authorizationService,
IElementEditingService elementEditingService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_authorizationService = authorizationService;
_elementEditingService = elementEditingService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}

[HttpDelete("{id:guid}")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(CancellationToken cancellationToken, Guid id)
{
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
User,
ElementPermissionResource.WithKeys(ActionElementDelete.ActionLetter, id),
AuthorizationPolicies.ElementPermissionByResource);

if (!authorizationResult.Succeeded)
{
return Forbidden();
}

Attempt<IElement?, ContentEditingOperationStatus> result = await _elementEditingService.DeleteAsync(id, CurrentUserKey(_backOfficeSecurityAccessor));

return result.Success
? Ok()
: ContentEditingOperationStatusResult(result.Status);
}
}
Loading
Loading