Skip to content

Added management API endpoint, service and repository for retrieval of references from the recycle bin #18882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
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.Models;
using Umbraco.Cms.Core.Services;

namespace Umbraco.Cms.Api.Management.Controllers.Document.RecycleBin;

[ApiVersion("1.0")]
public class ReferencedByDocumentRecycleBinController : DocumentRecycleBinControllerBase
{
private readonly ITrackedReferencesService _trackedReferencesService;
private readonly IRelationTypePresentationFactory _relationTypePresentationFactory;

public ReferencedByDocumentRecycleBinController(
IEntityService entityService,
IDocumentPresentationFactory documentPresentationFactory,
ITrackedReferencesService trackedReferencesService,
IRelationTypePresentationFactory relationTypePresentationFactory)
: base(entityService, documentPresentationFactory)
{
_trackedReferencesService = trackedReferencesService;
_relationTypePresentationFactory = relationTypePresentationFactory;
}

/// <summary>
/// Gets a paged list of tracked references for all items in the document recycle bin, so you can see where an item is being used.
/// </summary>
[HttpGet("referenced-by")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<IReferenceResponseModel>>> ReferencedBy(
CancellationToken cancellationToken,
int skip = 0,
int take = 20)
{
PagedModel<RelationItemModel> relationItems = await _trackedReferencesService.GetPagedRelationsForRecycleBinAsync(UmbracoObjectTypes.Document, skip, take, true);

var pagedViewModel = new PagedViewModel<IReferenceResponseModel>
{
Total = relationItems.Total,
Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItems.Items),
};

return pagedViewModel;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Http;
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.Models;
using Umbraco.Cms.Core.Services;

namespace Umbraco.Cms.Api.Management.Controllers.Media.RecycleBin;

[ApiVersion("1.0")]
public class ReferencedByMediaRecycleBinController : MediaRecycleBinControllerBase
{
private readonly ITrackedReferencesService _trackedReferencesService;
private readonly IRelationTypePresentationFactory _relationTypePresentationFactory;

public ReferencedByMediaRecycleBinController(
IEntityService entityService,
IMediaPresentationFactory mediaPresentationFactory,
ITrackedReferencesService trackedReferencesService,
IRelationTypePresentationFactory relationTypePresentationFactory)
: base(entityService, mediaPresentationFactory)
{
_trackedReferencesService = trackedReferencesService;
_relationTypePresentationFactory = relationTypePresentationFactory;
}

/// <summary>
/// Gets a paged list of tracked references for all items in the media recycle bin, so you can see where an item is being used.
/// </summary>
[HttpGet("referenced-by")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(PagedViewModel<IReferenceResponseModel>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedViewModel<IReferenceResponseModel>>> ReferencedBy(
CancellationToken cancellationToken,
int skip = 0,
int take = 20)
{
PagedModel<RelationItemModel> relationItems = await _trackedReferencesService.GetPagedRelationsForRecycleBinAsync(UmbracoObjectTypes.Media, skip, take, true);

var pagedViewModel = new PagedViewModel<IReferenceResponseModel>
{
Total = relationItems.Total,
Items = await _relationTypePresentationFactory.CreateReferenceResponseModelsAsync(relationItems.Items),
};

return pagedViewModel;
}
}
110 changes: 110 additions & 0 deletions src/Umbraco.Cms.Api.Management/OpenApi.json
Original file line number Diff line number Diff line change
Expand Up @@ -10611,6 +10611,61 @@
]
}
},
"/umbraco/management/api/v1/recycle-bin/document/referenced-by": {
"get": {
"tags": [
"Document"
],
"operationId": "GetRecycleBinDocumentReferencedBy",
"parameters": [
{
"name": "skip",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 0
}
},
{
"name": "take",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 20
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/PagedIReferenceResponseModel"
}
]
}
}
}
},
"401": {
"description": "The resource is protected and requires an authentication token"
},
"403": {
"description": "The authenticated user does not have access to this resource"
}
},
"security": [
{
"Backoffice User": [ ]
}
]
}
},
"/umbraco/management/api/v1/recycle-bin/document/root": {
"get": {
"tags": [
Expand Down Expand Up @@ -17762,6 +17817,61 @@
]
}
},
"/umbraco/management/api/v1/recycle-bin/media/referenced-by": {
"get": {
"tags": [
"Media"
],
"operationId": "GetRecycleBinMediaReferencedBy",
"parameters": [
{
"name": "skip",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 0
}
},
{
"name": "take",
"in": "query",
"schema": {
"type": "integer",
"format": "int32",
"default": 20
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/PagedIReferenceResponseModel"
}
]
}
}
}
},
"401": {
"description": "The resource is protected and requires an authentication token"
},
"403": {
"description": "The authenticated user does not have access to this resource"
}
},
"security": [
{
"Backoffice User": [ ]
}
]
}
},
"/umbraco/management/api/v1/recycle-bin/media/root": {
"get": {
"tags": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,29 @@
bool filterMustBeIsDependency,
out long totalRecords);

/// <summary>
/// Gets a paged result of items which are in relation with an item in the recycle bin.
/// </summary>
/// <param name="objectTypeKey">The Umbraco object type that has recycle bin support (currently Document or Media).</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>
/// <param name="totalRecords">The total count of the items with reference to the current item.</param>
/// <returns>An enumerable list of <see cref="RelationItem" /> objects.</returns>
IEnumerable<RelationItemModel> GetPagedRelationsForRecycleBin(
Guid objectTypeKey,
long skip,
long take,
bool filterMustBeIsDependency,
out long totalRecords)
{
totalRecords = 0;
return [];
}

Check warning on line 94 in src/Umbraco.Core/Persistence/Repositories/ITrackedReferencesRepository.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

❌ New issue: Excess Number of Function Arguments

GetPagedRelationsForRecycleBin has 5 arguments, threshold = 4. This function has too many arguments, indicating a lack of encapsulation. Avoid adding more arguments.

[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
IEnumerable<RelationItemModel> GetPagedRelationsForItem(
int id,
Expand Down
14 changes: 14 additions & 0 deletions src/Umbraco.Core/Services/ITrackedReferencesService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ public interface ITrackedReferencesService
/// <returns>A paged result of <see cref="RelationItemModel" /> objects.</returns>
Task<PagedModel<RelationItemModel>> GetPagedRelationsForItemAsync(Guid key, long skip, long take, bool filterMustBeIsDependency);

/// <summary>
/// Gets a paged result of items which are in relation with an item in the recycle bin.
/// </summary>
/// <param name="objectType">The Umbraco object type that has recycle bin support (currently Document or Media).</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>
Task<PagedModel<RelationItemModel>> GetPagedRelationsForRecycleBinAsync(UmbracoObjectTypes objectType, long skip, long take, bool filterMustBeIsDependency)
=> Task.FromResult(new PagedModel<RelationItemModel>(0, []));

[Obsolete("Use method that takes key (Guid) instead of id (int). This will be removed in Umbraco 15.")]
PagedModel<RelationItemModel> GetPagedDescendantsInReferences(int parentId, long skip, long take, bool filterMustBeIsDependency);

Expand Down
15 changes: 15 additions & 0 deletions src/Umbraco.Core/Services/TrackedReferencesService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.Extensions.DependencyInjection;

Check notice on line 1 in src/Umbraco.Core/Services/TrackedReferencesService.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

✅ Getting better: Primitive Obsession

The ratio of primitive types in function arguments decreases from 84.44% to 83.67%, threshold = 30.0%. The functions in this file have too many primitive types (e.g. int, double, float) in their function argument lists. Using many primitive types lead to the code smell Primitive Obsession. Avoid adding more primitive arguments.
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
Expand Down Expand Up @@ -92,6 +92,21 @@
return await Task.FromResult(pagedModel);
}

public async Task<PagedModel<RelationItemModel>> GetPagedRelationsForRecycleBinAsync(UmbracoObjectTypes objectType, long skip, long take, bool filterMustBeIsDependency)
{
Guid objectTypeKey = objectType switch
{
UmbracoObjectTypes.Document => Constants.ObjectTypes.Document,
UmbracoObjectTypes.Media => Constants.ObjectTypes.Media,
_ => throw new ArgumentOutOfRangeException(nameof(objectType), "Only documents and media have recycle bin support."),
};

using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
IEnumerable<RelationItemModel> items = _trackedReferencesRepository.GetPagedRelationsForRecycleBin(objectTypeKey, skip, take, filterMustBeIsDependency, out var totalItems);
var pagedModel = new PagedModel<RelationItemModel>(totalItems, items);
return await Task.FromResult(pagedModel);
}

[Obsolete("Use overload that takes key instead of id. This will be removed in Umbraco 15.")]
public PagedModel<RelationItemModel> GetPagedDescendantsInReferences(int parentId, long skip, long take, bool filterMustBeIsDependency)
{
Expand Down
Loading