Management API: Return not found from request for content references when entity does not exist (closes #20997) (#20999)
* Return not found when request for content references when entity does not exist.
* Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Move check for entity existence from controller to the service.
* Update OpenApi.json.
* Apply suggestions from code review
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Addressed points raised in code review.
* Update OpenApi.json
* Resolved breaking changes.
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit da94e0953b)
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing.Validation;
|
||||
using Umbraco.Cms.Core.PropertyEditors.Validation;
|
||||
@@ -12,7 +10,6 @@ namespace Umbraco.Cms.Api.Management.Controllers.Content;
|
||||
|
||||
public abstract class ContentControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
|
||||
protected IActionResult ContentEditingOperationStatusResult(ContentEditingOperationStatus status)
|
||||
=> OperationStatusResult(status, problemDetailsBuilder => status switch
|
||||
{
|
||||
@@ -98,6 +95,17 @@ public abstract class ContentControllerBase : ManagementApiControllerBase
|
||||
.Build()),
|
||||
});
|
||||
|
||||
protected IActionResult GetReferencesOperationStatusResult(GetReferencesOperationStatus status)
|
||||
=> OperationStatusResult(status, problemDetailsBuilder => status switch
|
||||
{
|
||||
GetReferencesOperationStatus.ContentNotFound => NotFound(problemDetailsBuilder
|
||||
.WithTitle("The requested content could not be found")
|
||||
.Build()),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, problemDetailsBuilder
|
||||
.WithTitle("Unknown get references operation status.")
|
||||
.Build()),
|
||||
});
|
||||
|
||||
protected IActionResult ContentEditingOperationStatusResult<TContentModelBase, TValueModel, TVariantModel>(
|
||||
ContentEditingOperationStatus status,
|
||||
TContentModelBase requestModel,
|
||||
|
||||
@@ -4,8 +4,10 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.TrackedReferences;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Document.References;
|
||||
|
||||
@@ -15,22 +17,16 @@ public class ReferencedByDocumentController : DocumentControllerBase
|
||||
private readonly ITrackedReferencesService _trackedReferencesService;
|
||||
private readonly IRelationTypePresentationFactory _relationTypePresentationFactory;
|
||||
|
||||
public ReferencedByDocumentController(ITrackedReferencesService trackedReferencesService, IRelationTypePresentationFactory relationTypePresentationFactory)
|
||||
public ReferencedByDocumentController(
|
||||
ITrackedReferencesService trackedReferencesService,
|
||||
IRelationTypePresentationFactory relationTypePresentationFactory)
|
||||
{
|
||||
_trackedReferencesService = trackedReferencesService;
|
||||
_relationTypePresentationFactory = relationTypePresentationFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged list of tracked references for the current item, so you can see where an item is being used.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
||||
/// This is basically finding parents of relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-by")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
|
||||
[Obsolete("Use the ReferencedBy2 action method instead. Scheduled for removal in Umbraco 19, when ReferencedBy2 will be renamed back to ReferencedBy.")]
|
||||
[NonAction]
|
||||
public async Task<ActionResult<PagedViewModel<IReferenceResponseModel>>> ReferencedBy(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
@@ -47,4 +43,37 @@ public class ReferencedByDocumentController : DocumentControllerBase
|
||||
|
||||
return pagedViewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged list of tracked references for the current item, so you can see where an item is being used.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
||||
/// This is basically finding parents of relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-by")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ReferencedBy2(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus> relationItemsAttempt = await _trackedReferencesService.GetPagedRelationsForItemAsync(id, UmbracoObjectTypes.Document, skip, take, true);
|
||||
|
||||
if (relationItemsAttempt.Success is false)
|
||||
{
|
||||
return GetReferencesOperationStatusResult(relationItemsAttempt.Status);
|
||||
}
|
||||
|
||||
var pagedViewModel = new PagedViewModel<IReferenceResponseModel>
|
||||
{
|
||||
Total = relationItemsAttempt.Result.Total,
|
||||
Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItemsAttempt.Result.Items),
|
||||
};
|
||||
|
||||
return Ok(pagedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
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.References;
|
||||
|
||||
@@ -15,12 +17,32 @@ public class ReferencedDescendantsDocumentController : DocumentControllerBase
|
||||
private readonly ITrackedReferencesService _trackedReferencesSkipTakeService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public ReferencedDescendantsDocumentController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper)
|
||||
public ReferencedDescendantsDocumentController(
|
||||
ITrackedReferencesService trackedReferencesSkipTakeService,
|
||||
IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_trackedReferencesSkipTakeService = trackedReferencesSkipTakeService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
[Obsolete("Use the ReferencedDescendants2 action method instead. Scheduled for removal in Umbraco 19, when ReferencedDescendants2 will be renamed back to ReferencedDescendants.")]
|
||||
[NonAction]
|
||||
public async Task<ActionResult<PagedViewModel<ReferenceByIdModel>>> ReferencedDescendants(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
PagedModel<RelationItemModel> relationItems = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, skip, take, true);
|
||||
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||
{
|
||||
Total = relationItems.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(relationItems.Items),
|
||||
};
|
||||
|
||||
return pagedViewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged list of the descendant nodes of the current item used in any kind of relation.
|
||||
/// </summary>
|
||||
@@ -32,19 +54,26 @@ public class ReferencedDescendantsDocumentController : DocumentControllerBase
|
||||
[HttpGet("{id:guid}/referenced-descendants")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<ReferenceByIdModel>), StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<PagedViewModel<ReferenceByIdModel>>> ReferencedDescendants(
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ReferencedDescendants2(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
PagedModel<RelationItemModel> relationItems = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, skip, take, true);
|
||||
Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus> relationItemsAttempt = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, UmbracoObjectTypes.Document, skip, take, true);
|
||||
|
||||
if (relationItemsAttempt.Success is false)
|
||||
{
|
||||
return GetReferencesOperationStatusResult(relationItemsAttempt.Status);
|
||||
}
|
||||
|
||||
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||
{
|
||||
Total = relationItems.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(relationItems.Items),
|
||||
Total = relationItemsAttempt.Result.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(relationItemsAttempt.Result.Items),
|
||||
};
|
||||
|
||||
return pagedViewModel;
|
||||
return Ok(pagedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.TrackedReferences;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media.References;
|
||||
|
||||
@@ -15,22 +17,16 @@ public class ReferencedByMediaController : MediaControllerBase
|
||||
private readonly ITrackedReferencesService _trackedReferencesService;
|
||||
private readonly IRelationTypePresentationFactory _relationTypePresentationFactory;
|
||||
|
||||
public ReferencedByMediaController(ITrackedReferencesService trackedReferencesService, IRelationTypePresentationFactory relationTypePresentationFactory)
|
||||
public ReferencedByMediaController(
|
||||
ITrackedReferencesService trackedReferencesService,
|
||||
IRelationTypePresentationFactory relationTypePresentationFactory)
|
||||
{
|
||||
_trackedReferencesService = trackedReferencesService;
|
||||
_relationTypePresentationFactory = relationTypePresentationFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a page list of tracked references for the current item, so you can see where an item is being used.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
||||
/// This is basically finding parents of relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-by")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
|
||||
[Obsolete("Use the ReferencedBy2 action method instead. Scheduled for removal in Umbraco 19, when ReferencedBy2 will be renamed back to ReferencedBy.")]
|
||||
[NonAction]
|
||||
public async Task<ActionResult<PagedViewModel<IReferenceResponseModel>>> ReferencedBy(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
@@ -47,4 +43,37 @@ public class ReferencedByMediaController : MediaControllerBase
|
||||
|
||||
return pagedViewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a page list of tracked references for the current item, so you can see where an item is being used.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
||||
/// This is basically finding parents of relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-by")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ReferencedBy2(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus> relationItemsAttempt = await _trackedReferencesService.GetPagedRelationsForItemAsync(id, UmbracoObjectTypes.Media, skip, take, true);
|
||||
|
||||
if (relationItemsAttempt.Success is false)
|
||||
{
|
||||
return GetReferencesOperationStatusResult(relationItemsAttempt.Status);
|
||||
}
|
||||
|
||||
var pagedViewModel = new PagedViewModel<IReferenceResponseModel>
|
||||
{
|
||||
Total = relationItemsAttempt.Result.Total,
|
||||
Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItemsAttempt.Result.Items),
|
||||
};
|
||||
|
||||
return Ok(pagedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
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.Media.References;
|
||||
|
||||
@@ -14,13 +16,32 @@ public class ReferencedDescendantsMediaController : MediaControllerBase
|
||||
{
|
||||
private readonly ITrackedReferencesService _trackedReferencesSkipTakeService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public ReferencedDescendantsMediaController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper)
|
||||
public ReferencedDescendantsMediaController(
|
||||
ITrackedReferencesService trackedReferencesSkipTakeService,
|
||||
IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_trackedReferencesSkipTakeService = trackedReferencesSkipTakeService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
[Obsolete("Use the ReferencedDescendants2 action method instead. Scheduled for removal in Umbraco 19, when ReferencedDescendants2 will be renamed back to ReferencedDescendants.")]
|
||||
[NonAction]
|
||||
public async Task<ActionResult<PagedViewModel<ReferenceByIdModel>>> ReferencedDescendants(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
PagedModel<RelationItemModel> relationItems = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, skip, take, true);
|
||||
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||
{
|
||||
Total = relationItems.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(relationItems.Items),
|
||||
};
|
||||
|
||||
return pagedViewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a page list of the child nodes of the current item used in any kind of relation.
|
||||
/// </summary>
|
||||
@@ -32,19 +53,26 @@ public class ReferencedDescendantsMediaController : MediaControllerBase
|
||||
[HttpGet("{id:guid}/referenced-descendants")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<ReferenceByIdModel>), StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<PagedViewModel<ReferenceByIdModel>>> ReferencedDescendants(
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ReferencedDescendants2(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
PagedModel<RelationItemModel> relationItems = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, skip, take, true);
|
||||
Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus> relationItemsAttempt = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, UmbracoObjectTypes.Media, skip, take, true);
|
||||
|
||||
if (relationItemsAttempt.Success is false)
|
||||
{
|
||||
return GetReferencesOperationStatusResult(relationItemsAttempt.Status);
|
||||
}
|
||||
|
||||
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||
{
|
||||
Total = relationItems.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(relationItems.Items),
|
||||
Total = relationItemsAttempt.Result.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(relationItemsAttempt.Result.Items),
|
||||
};
|
||||
|
||||
return pagedViewModel;
|
||||
return Ok(pagedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.TrackedReferences;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Member.References;
|
||||
|
||||
@@ -15,22 +17,16 @@ public class ReferencedByMemberController : MemberControllerBase
|
||||
private readonly ITrackedReferencesService _trackedReferencesService;
|
||||
private readonly IRelationTypePresentationFactory _relationTypePresentationFactory;
|
||||
|
||||
public ReferencedByMemberController(ITrackedReferencesService trackedReferencesService, IRelationTypePresentationFactory relationTypePresentationFactory)
|
||||
public ReferencedByMemberController(
|
||||
ITrackedReferencesService trackedReferencesService,
|
||||
IRelationTypePresentationFactory relationTypePresentationFactory)
|
||||
{
|
||||
_trackedReferencesService = trackedReferencesService;
|
||||
_relationTypePresentationFactory = relationTypePresentationFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a page list of tracked references for the current item, so you can see where an item is being used.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
||||
/// This is basically finding parents of relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-by")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
|
||||
[Obsolete("Use the ReferencedBy2 action method instead. Scheduled for removal in Umbraco 19, when ReferencedBy2 will be renamed back to ReferencedBy.")]
|
||||
[NonAction]
|
||||
public async Task<ActionResult<PagedViewModel<IReferenceResponseModel>>> ReferencedBy(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
@@ -47,4 +43,37 @@ public class ReferencedByMemberController : MemberControllerBase
|
||||
|
||||
return pagedViewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a page list of tracked references for the current item, so you can see where an item is being used.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used by info tabs on content, media etc. and for the delete and unpublish of single items.
|
||||
/// This is basically finding parents of relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-by")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ReferencedBy2(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus> relationItemsAttempt = await _trackedReferencesService.GetPagedRelationsForItemAsync(id, UmbracoObjectTypes.Member, skip, take, true);
|
||||
|
||||
if (relationItemsAttempt.Success is false)
|
||||
{
|
||||
return GetReferencesOperationStatusResult(relationItemsAttempt.Status);
|
||||
}
|
||||
|
||||
var pagedViewModel = new PagedViewModel<IReferenceResponseModel>
|
||||
{
|
||||
Total = relationItemsAttempt.Result.Total,
|
||||
Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItemsAttempt.Result.Items),
|
||||
};
|
||||
|
||||
return Ok(pagedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
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.Member.References;
|
||||
|
||||
@@ -15,23 +17,16 @@ public class ReferencedDescendantsMemberController : MemberControllerBase
|
||||
private readonly ITrackedReferencesService _trackedReferencesSkipTakeService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public ReferencedDescendantsMemberController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper)
|
||||
public ReferencedDescendantsMemberController(
|
||||
ITrackedReferencesService trackedReferencesSkipTakeService,
|
||||
IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_trackedReferencesSkipTakeService = trackedReferencesSkipTakeService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a page list of the child nodes of the current item used in any kind of relation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used when deleting and unpublishing a single item to check if this item has any descending items that are in any
|
||||
/// kind of relation.
|
||||
/// This is basically finding the descending items which are children in relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-descendants")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<ReferenceByIdModel>), StatusCodes.Status200OK)]
|
||||
[Obsolete("Use the ReferencedDescendants2 action method instead. Scheduled for removal in Umbraco 19, when ReferencedDescendants2 will be renamed back to ReferencedDescendants.")]
|
||||
[NonAction]
|
||||
public async Task<ActionResult<PagedViewModel<ReferenceByIdModel>>> ReferencedDescendants(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
@@ -47,4 +42,38 @@ public class ReferencedDescendantsMemberController : MemberControllerBase
|
||||
|
||||
return pagedViewModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a page list of the child nodes of the current item used in any kind of relation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used when deleting and unpublishing a single item to check if this item has any descending items that are in any
|
||||
/// kind of relation.
|
||||
/// This is basically finding the descending items which are children in relations.
|
||||
/// </remarks>
|
||||
[HttpGet("{id:guid}/referenced-descendants")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<ReferenceByIdModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> ReferencedDescendants2(
|
||||
CancellationToken cancellationToken,
|
||||
Guid id,
|
||||
int skip = 0,
|
||||
int take = 20)
|
||||
{
|
||||
Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus> relationItemsAttempt = await _trackedReferencesSkipTakeService.GetPagedDescendantsInReferencesAsync(id, UmbracoObjectTypes.Member, skip, take, true);
|
||||
|
||||
if (relationItemsAttempt.Success is false)
|
||||
{
|
||||
return GetReferencesOperationStatusResult(relationItemsAttempt.Status);
|
||||
}
|
||||
|
||||
var pagedViewModel = new PagedViewModel<ReferenceByIdModel>
|
||||
{
|
||||
Total = relationItemsAttempt.Result.Total,
|
||||
Items = _umbracoMapper.MapEnumerable<RelationItemModel, ReferenceByIdModel>(relationItemsAttempt.Result.Items),
|
||||
};
|
||||
|
||||
return Ok(pagedViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9628,6 +9628,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
},
|
||||
@@ -9692,6 +9706,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
},
|
||||
@@ -17348,6 +17376,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
},
|
||||
@@ -17412,6 +17454,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
},
|
||||
@@ -21653,6 +21709,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
},
|
||||
@@ -21717,6 +21787,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
},
|
||||
@@ -49575,4 +49659,4 @@
|
||||
"name": "Webhook"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -16,8 +17,27 @@ public interface ITrackedReferencesService
|
||||
/// dependencies (isDependency field is set to true).
|
||||
/// </param>
|
||||
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
|
||||
[Obsolete("Use GetPagedRelationsForItemAsync which returns an Attempt with operation status. Scheduled for removal in Umbraco 19.")]
|
||||
Task<PagedModel<RelationItemModel>> GetPagedRelationsForItemAsync(Guid key, long skip, long take, bool filterMustBeIsDependency);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged result of items which are in relation with the current item.
|
||||
/// Basically, shows the items which depend on the current item.
|
||||
/// </summary>
|
||||
/// <param name="key">The identifier of the entity to retrieve relations for.</param>
|
||||
/// <param name="objectType">The Umbraco object type of the parent.</param>
|
||||
/// <param name="skip">The amount of items to skip</param>
|
||||
/// <param name="take">The amount of items to take.</param>
|
||||
/// <param name="filterMustBeIsDependency">
|
||||
/// A boolean indicating whether to filter only the RelationTypes which are
|
||||
/// dependencies (isDependency field is set to true).
|
||||
/// </param>
|
||||
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
|
||||
async Task<Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus>> GetPagedRelationsForItemAsync(Guid key, UmbracoObjectTypes objectType, long skip, long take, bool filterMustBeIsDependency)
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
=> Attempt.SucceedWithStatus(GetReferencesOperationStatus.Success, await GetPagedRelationsForItemAsync(key, skip, take, filterMustBeIsDependency));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged result of items which are in relation with an item in the recycle bin.
|
||||
/// </summary>
|
||||
@@ -42,8 +62,26 @@ public interface ITrackedReferencesService
|
||||
/// dependencies (isDependency field is set to true).
|
||||
/// </param>
|
||||
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
|
||||
[Obsolete("Use GetPagedDescendantsInReferencesAsync which returns an Attempt with operation status. Scheduled for removal in Umbraco 19.")]
|
||||
Task<PagedModel<RelationItemModel>> GetPagedDescendantsInReferencesAsync(Guid parentKey, long skip, long take, bool filterMustBeIsDependency);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged result of the descending items that have any references, given a parent id.
|
||||
/// </summary>
|
||||
/// <param name="parentKey">The unique identifier of the parent to retrieve descendants for.</param>
|
||||
/// <param name="objectType">The Umbraco object type of the parent.</param>
|
||||
/// <param name="skip">The amount of items to skip</param>
|
||||
/// <param name="take">The amount of items to take.</param>
|
||||
/// <param name="filterMustBeIsDependency">
|
||||
/// A boolean indicating whether to filter only the RelationTypes which are
|
||||
/// dependencies (isDependency field is set to true).
|
||||
/// </param>
|
||||
/// <returns>An <see cref="Attempt"/> wrapping a paged result of <see cref="RelationItemModel" /> objects.</returns>
|
||||
async Task<Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus>> GetPagedDescendantsInReferencesAsync(Guid parentKey, UmbracoObjectTypes objectType, long skip, long take, bool filterMustBeIsDependency)
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
=> Attempt.SucceedWithStatus(GetReferencesOperationStatus.Success, await GetPagedDescendantsInReferencesAsync(parentKey, skip, take, filterMustBeIsDependency));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
/// <summary>
|
||||
/// Gets a paged result of items used in any kind of relation from selected integer ids.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum GetReferencesOperationStatus
|
||||
{
|
||||
Success,
|
||||
ContentNotFound
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -20,6 +22,7 @@ public class TrackedReferencesService : ITrackedReferencesService
|
||||
_entityService = entityService;
|
||||
}
|
||||
|
||||
[Obsolete("Use the GetPagedRelationsForItemAsync overload which returns an Attempt with operation status. Scheduled for removal in Umbraco 19.")]
|
||||
public Task<PagedModel<RelationItemModel>> GetPagedRelationsForItemAsync(Guid key, long skip, long take, bool filterMustBeIsDependency)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
@@ -29,6 +32,21 @@ public class TrackedReferencesService : ITrackedReferencesService
|
||||
return Task.FromResult(pagedModel);
|
||||
}
|
||||
|
||||
public async Task<Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus>> GetPagedRelationsForItemAsync(Guid key, UmbracoObjectTypes objectType, long skip, long take, bool filterMustBeIsDependency)
|
||||
{
|
||||
IEntitySlim? entity = _entityService.Get(key, objectType);
|
||||
if (entity is null)
|
||||
{
|
||||
return Attempt.FailWithStatus(GetReferencesOperationStatus.ContentNotFound, new PagedModel<RelationItemModel>());
|
||||
}
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete (but using whilst it exists to avoid code repetition)
|
||||
PagedModel<RelationItemModel> pagedModel = await GetPagedRelationsForItemAsync(key, skip, take, filterMustBeIsDependency);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
return Attempt.SucceedWithStatus(GetReferencesOperationStatus.Success, pagedModel);
|
||||
}
|
||||
|
||||
public Task<PagedModel<RelationItemModel>> GetPagedRelationsForRecycleBinAsync(UmbracoObjectTypes objectType, long skip, long take, bool filterMustBeIsDependency)
|
||||
{
|
||||
Guid objectTypeKey = objectType switch
|
||||
@@ -44,6 +62,7 @@ public class TrackedReferencesService : ITrackedReferencesService
|
||||
return Task.FromResult(pagedModel);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetPagedDescendantsInReferencesAsync which returns an Attempt with operation status. Scheduled for removal in Umbraco 19.")]
|
||||
public Task<PagedModel<RelationItemModel>> GetPagedDescendantsInReferencesAsync(Guid parentKey, long skip, long take, bool filterMustBeIsDependency)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
@@ -59,6 +78,21 @@ public class TrackedReferencesService : ITrackedReferencesService
|
||||
return Task.FromResult(pagedModel);
|
||||
}
|
||||
|
||||
public async Task<Attempt<PagedModel<RelationItemModel>, GetReferencesOperationStatus>> GetPagedDescendantsInReferencesAsync(Guid parentKey, UmbracoObjectTypes objectType, long skip, long take, bool filterMustBeIsDependency)
|
||||
{
|
||||
IEntitySlim? entity = _entityService.Get(parentKey, objectType);
|
||||
if (entity is null)
|
||||
{
|
||||
return Attempt.FailWithStatus(GetReferencesOperationStatus.ContentNotFound, new PagedModel<RelationItemModel>());
|
||||
}
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete (but using whilst it exists to avoid code repetition)
|
||||
PagedModel<RelationItemModel> pagedModel = await GetPagedDescendantsInReferencesAsync(parentKey, skip, take, filterMustBeIsDependency);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
return Attempt.SucceedWithStatus(GetReferencesOperationStatus.Success, pagedModel);
|
||||
}
|
||||
|
||||
public Task<PagedModel<RelationItemModel>> GetPagedItemsWithRelationsAsync(ISet<Guid> keys, long skip, long take, bool filterMustBeIsDependency)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
|
||||
@@ -5,6 +5,7 @@ using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Relations;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
@@ -77,25 +78,55 @@ internal class TrackedReferencesServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
var sut = GetRequiredService<ITrackedReferencesService>();
|
||||
|
||||
var actual = await sut.GetPagedRelationsForItemAsync(Root1.Key, 0, 10, true);
|
||||
var actual = await sut.GetPagedRelationsForItemAsync(Root1.Key, UmbracoObjectTypes.Document, 0, 10, true);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(1, actual.Total);
|
||||
var item = actual.Items.FirstOrDefault();
|
||||
Assert.IsTrue(actual.Success);
|
||||
Assert.AreEqual(1, actual.Result.Total);
|
||||
var item = actual.Result.Items.FirstOrDefault();
|
||||
Assert.AreEqual(Root2.ContentType.Alias, item?.ContentTypeAlias);
|
||||
Assert.AreEqual(Root2.Key, item?.NodeKey);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Get_Relations_For_Non_Existing_Page_Returns_Not_Found()
|
||||
{
|
||||
var sut = GetRequiredService<ITrackedReferencesService>();
|
||||
|
||||
var actual = await sut.GetPagedRelationsForItemAsync(Guid.NewGuid(), UmbracoObjectTypes.Document, 0, 10, true);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsFalse(actual.Success);
|
||||
Assert.AreEqual(GetReferencesOperationStatus.ContentNotFound, actual.Status);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Get_Descendants_In_References_For_Non_Existing_Page_Returns_Not_Found()
|
||||
{
|
||||
var sut = GetRequiredService<ITrackedReferencesService>();
|
||||
|
||||
var actual = await sut.GetPagedDescendantsInReferencesAsync(Guid.NewGuid(), UmbracoObjectTypes.Document, 0, 10, true);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsFalse(actual.Success);
|
||||
Assert.AreEqual(GetReferencesOperationStatus.ContentNotFound, actual.Status);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Does_Not_Return_References_If_Item_Is_Not_Referenced()
|
||||
{
|
||||
var sut = GetRequiredService<ITrackedReferencesService>();
|
||||
|
||||
var actual = await sut.GetPagedRelationsForItemAsync(Root2.Key, 0, 10, true);
|
||||
var actual = await sut.GetPagedRelationsForItemAsync(Root2.Key, UmbracoObjectTypes.Document, 0, 10, true);
|
||||
|
||||
Assert.AreEqual(0, actual.Total);
|
||||
Assert.IsTrue(actual.Success);
|
||||
Assert.AreEqual(0, actual.Result.Total);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
Reference in New Issue
Block a user