Document and Media restore endpoints (#15681)
* Added Endpoint to get Document restore information * Add media version of original paent recycle bin update document permission regisered interfaces * Added restore endpoints * PR feedback and other cleanup * Update orignal root parent logic & shrank return model --------- Co-authored-by: Sven Geusens <sge@umbraco.dk> Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
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.Security.Authorization.Content;
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Document.RecycleBin;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class OriginalParentDocumentRecycleBinController : DocumentRecycleBinControllerBase
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IDocumentPresentationFactory _documentPresentationFactory;
|
||||
private readonly IDocumentRecycleBinQueryService _documentRecycleBinQueryService;
|
||||
|
||||
public OriginalParentDocumentRecycleBinController(
|
||||
IEntityService entityService,
|
||||
IAuthorizationService authorizationService,
|
||||
IDocumentPresentationFactory documentPresentationFactory,
|
||||
IDocumentRecycleBinQueryService documentRecycleBinQueryService)
|
||||
: base(entityService, documentPresentationFactory)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_documentPresentationFactory = documentPresentationFactory;
|
||||
_documentRecycleBinQueryService = documentRecycleBinQueryService;
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}/original-parent")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ReferenceByIdModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> OriginalParent(Guid id)
|
||||
{
|
||||
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
|
||||
User,
|
||||
ContentPermissionResource.RecycleBin(ActionBrowse.ActionLetter),
|
||||
AuthorizationPolicies.ContentPermissionByResource);
|
||||
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbidden();
|
||||
}
|
||||
|
||||
Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType> getParentAttempt = await _documentRecycleBinQueryService.GetOriginalParentAsync(id);
|
||||
return getParentAttempt.Success switch
|
||||
{
|
||||
true when getParentAttempt.Status == RecycleBinQueryResultType.Success
|
||||
=> Ok(new ReferenceByIdModel(getParentAttempt.Result!.Key)),
|
||||
true when getParentAttempt.Status == RecycleBinQueryResultType.ParentIsRoot
|
||||
=> Ok(null),
|
||||
_ => MapAttemptFailure(getParentAttempt.Status),
|
||||
};
|
||||
}
|
||||
|
||||
private IActionResult MapAttemptFailure(RecycleBinQueryResultType status)
|
||||
=> MapRecycleBinQueryAttemptFailure(status, "document");
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
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.Security.Authorization.Content;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
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.Document.RecycleBin;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class RestoreDocumentRecycleBinController : DocumentRecycleBinControllerBase
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IContentEditingService _contentEditingService;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public RestoreDocumentRecycleBinController(
|
||||
IAuthorizationService authorizationService,
|
||||
IContentEditingService contentEditingService,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IDocumentPresentationFactory documentPresentationFactory)
|
||||
: base(entityService,documentPresentationFactory)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_contentEditingService = contentEditingService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}/restore")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> Restore(Guid id, MoveMediaRequestModel moveDocumentRequestModel)
|
||||
{
|
||||
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
|
||||
User,
|
||||
ContentPermissionResource.RecycleBin(ActionMove.ActionLetter),
|
||||
AuthorizationPolicies.ContentPermissionByResource);
|
||||
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbidden();
|
||||
}
|
||||
|
||||
Attempt<IContent?, ContentEditingOperationStatus> result = await _contentEditingService.RestoreAsync(
|
||||
id,
|
||||
moveDocumentRequestModel.Target?.Id,
|
||||
CurrentUserKey(_backOfficeSecurityAccessor));
|
||||
|
||||
return result.Success
|
||||
? Ok()
|
||||
: ContentEditingOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
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.Security.Authorization.Media;
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media.Item;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media.RecycleBin;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class OriginalParentMediaRecycleBinController : MediaRecycleBinControllerBase
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IMediaPresentationFactory _mediaPresentationFactory;
|
||||
private readonly IMediaRecycleBinQueryService _mediaRecycleBinQueryService;
|
||||
|
||||
public OriginalParentMediaRecycleBinController(
|
||||
IEntityService entityService,
|
||||
IAuthorizationService authorizationService,
|
||||
IMediaPresentationFactory mediaPresentationFactory,
|
||||
IMediaRecycleBinQueryService mediaRecycleBinQueryService)
|
||||
: base(entityService, mediaPresentationFactory)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_mediaPresentationFactory = mediaPresentationFactory;
|
||||
_mediaRecycleBinQueryService = mediaRecycleBinQueryService;
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}/original-parent")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(ReferenceByIdModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> OriginalParent(Guid id)
|
||||
{
|
||||
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
|
||||
User,
|
||||
MediaPermissionResource.RecycleBin(),
|
||||
AuthorizationPolicies.MediaPermissionByResource);
|
||||
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbidden();
|
||||
}
|
||||
|
||||
Attempt<IMediaEntitySlim?, RecycleBinQueryResultType> getParentAttempt = await _mediaRecycleBinQueryService.GetOriginalParentAsync(id);
|
||||
return getParentAttempt.Success switch
|
||||
{
|
||||
true when getParentAttempt.Status == RecycleBinQueryResultType.Success
|
||||
=> Ok(new ReferenceByIdModel(getParentAttempt.Result!.Key)),
|
||||
true when getParentAttempt.Status == RecycleBinQueryResultType.ParentIsRoot
|
||||
=> Ok(null),
|
||||
_ => MapAttemptFailure(getParentAttempt.Status),
|
||||
};
|
||||
}
|
||||
|
||||
private IActionResult MapAttemptFailure(RecycleBinQueryResultType status)
|
||||
=> MapRecycleBinQueryAttemptFailure(status, "media item");
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
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.Security.Authorization.Media;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
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.Media.RecycleBin;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class RestoreMediaRecycleBinController : MediaRecycleBinControllerBase
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IMediaEditingService _mediaEditingService;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public RestoreMediaRecycleBinController(
|
||||
IAuthorizationService authorizationService,
|
||||
IMediaEditingService mediaEditingService,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IMediaPresentationFactory mediaPresentationFactory)
|
||||
: base(entityService,mediaPresentationFactory)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_mediaEditingService = mediaEditingService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}/restore")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> Restore(Guid id, MoveMediaRequestModel moveDocumentRequestModel)
|
||||
{
|
||||
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
|
||||
User,
|
||||
MediaPermissionResource.RecycleBin(),
|
||||
AuthorizationPolicies.MediaPermissionByResource);
|
||||
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbidden();
|
||||
}
|
||||
|
||||
Attempt<IMedia?, ContentEditingOperationStatus> result = await _mediaEditingService.RestoreAsync(
|
||||
id,
|
||||
moveDocumentRequestModel.Target?.Id,
|
||||
CurrentUserKey(_backOfficeSecurityAccessor));
|
||||
|
||||
return result.Success
|
||||
? Ok()
|
||||
: ContentEditingOperationStatusResult(result.Status);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Umbraco.Cms.Api.Management.ViewModels.RecycleBin;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.RecycleBin;
|
||||
|
||||
@@ -94,6 +95,31 @@ public abstract class RecycleBinControllerBase<TItem> : ContentControllerBase
|
||||
.Build()),
|
||||
});
|
||||
|
||||
protected IActionResult MapRecycleBinQueryAttemptFailure(RecycleBinQueryResultType status, string contentType)
|
||||
=> OperationStatusResult(status, problemDetailsBuilder => status switch
|
||||
{
|
||||
RecycleBinQueryResultType.NotFound => NotFound(problemDetailsBuilder
|
||||
.WithTitle($"The {contentType} could not be found")
|
||||
.Build()),
|
||||
RecycleBinQueryResultType.NotTrashed => BadRequest(problemDetailsBuilder
|
||||
.WithTitle($"The {contentType} is not trashed")
|
||||
.WithDetail($"The {contentType} needs to be trashed for the parent-before-recycled relation to be created.")
|
||||
.Build()),
|
||||
RecycleBinQueryResultType.NoParentRecycleRelation => StatusCode(StatusCodes.Status500InternalServerError, problemDetailsBuilder
|
||||
.WithTitle("The parent relation could not be found")
|
||||
.WithDetail($"The relation between the parent and the {contentType} that should have been created when the {contentType} was deleted could not be found.")
|
||||
.Build()),
|
||||
RecycleBinQueryResultType.ParentNotFound => NotFound(problemDetailsBuilder
|
||||
.WithTitle($"The original {contentType} parent could not be found")
|
||||
.Build()),
|
||||
RecycleBinQueryResultType.ParentIsTrashed => NotFound(problemDetailsBuilder
|
||||
.WithTitle($"The original {contentType} parent is in the recycle bin")
|
||||
.Build()),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, problemDetailsBuilder
|
||||
.WithTitle("Unknown recycle bin query type.")
|
||||
.Build()),
|
||||
});
|
||||
|
||||
private IEntitySlim[] GetPagedRootEntities(long pageNumber, int pageSize, out long totalItems)
|
||||
{
|
||||
IEntitySlim[] rootEntities = _entityService
|
||||
|
||||
@@ -37,6 +37,7 @@ using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.ContentTypeEditing;
|
||||
using Umbraco.Cms.Core.DynamicRoot;
|
||||
using Umbraco.Cms.Core.Services.FileSystem;
|
||||
using Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
using Umbraco.Cms.Core.Sync;
|
||||
using Umbraco.Cms.Core.Telemetry;
|
||||
using Umbraco.Cms.Core.Templates;
|
||||
@@ -376,10 +377,13 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
Services.AddUnique<IDataTypeConfigurationCache, DataTypeConfigurationCache>();
|
||||
Services.AddNotificationHandler<DataTypeCacheRefresherNotification, DataTypeConfigurationCacheRefresher>();
|
||||
|
||||
//Two factor providers
|
||||
// Two factor providers
|
||||
Services.AddUnique<ITwoFactorLoginService, TwoFactorLoginService>();
|
||||
Services.AddUnique<IUserTwoFactorLoginService, UserTwoFactorLoginService>();
|
||||
|
||||
// Add Query services
|
||||
Services.AddUnique<IDocumentRecycleBinQueryService, DocumentRecycleBinQueryService>();
|
||||
Services.AddUnique<IMediaRecycleBinQueryService, MediaRecycleBinQueryService>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,9 @@ internal sealed class ContentEditingService
|
||||
public async Task<Attempt<IContent?, ContentEditingOperationStatus>> MoveAsync(Guid key, Guid? parentKey, Guid userKey)
|
||||
=> await HandleMoveAsync(key, parentKey, userKey);
|
||||
|
||||
public async Task<Attempt<IContent?, ContentEditingOperationStatus>> RestoreAsync(Guid key, Guid? parentKey, Guid userKey)
|
||||
=> await HandleMoveAsync(key, parentKey, userKey, true);
|
||||
|
||||
public async Task<Attempt<IContent?, ContentEditingOperationStatus>> CopyAsync(Guid key, Guid? parentKey, bool relateToOriginal, bool includeDescendants, Guid userKey)
|
||||
=> await HandleCopyAsync(key, parentKey, relateToOriginal, includeDescendants, userKey);
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ internal abstract class ContentEditingServiceBase<TContent, TContentType, TConte
|
||||
return OperationResultToAttempt(content, deleteResult);
|
||||
}
|
||||
|
||||
protected async Task<Attempt<TContent?, ContentEditingOperationStatus>> HandleMoveAsync(Guid key, Guid? parentKey, Guid userKey)
|
||||
protected async Task<Attempt<TContent?, ContentEditingOperationStatus>> HandleMoveAsync(Guid key, Guid? parentKey, Guid userKey, bool mustBeInRecycleBin = false)
|
||||
{
|
||||
using ICoreScope scope = CoreScopeProvider.CreateCoreScope();
|
||||
TContent? content = ContentService.GetById(key);
|
||||
@@ -178,6 +178,11 @@ internal abstract class ContentEditingServiceBase<TContent, TContentType, TConte
|
||||
return await Task.FromResult(Attempt.FailWithStatus(ContentEditingOperationStatus.NotFound, content));
|
||||
}
|
||||
|
||||
if (mustBeInRecycleBin && content.Trashed is false)
|
||||
{
|
||||
return await Task.FromResult(Attempt.FailWithStatus<TContent?, ContentEditingOperationStatus>(ContentEditingOperationStatus.NotInTrash, content));
|
||||
}
|
||||
|
||||
TContentType contentType = ContentTypeService.Get(content.ContentType.Key)!;
|
||||
|
||||
TContent? parent = TryGetAndValidateParent(parentKey, contentType, out ContentEditingOperationStatus operationStatus);
|
||||
|
||||
@@ -34,4 +34,6 @@ public interface IContentEditingService
|
||||
/// Deletes a Content Item whether it is in the recycle bin or not.
|
||||
/// </summary>
|
||||
Task<Attempt<IContent?, ContentEditingOperationStatus>> DeleteAsync(Guid key, Guid userKey);
|
||||
|
||||
Task<Attempt<IContent?, ContentEditingOperationStatus>> RestoreAsync(Guid key, Guid? parentKey, Guid userKey);
|
||||
}
|
||||
|
||||
@@ -25,4 +25,6 @@ public interface IMediaEditingService
|
||||
|
||||
Task<ContentEditingOperationStatus> SortAsync(Guid? parentKey, IEnumerable<SortingModel> sortingModels, Guid userKey);
|
||||
Task<Attempt<IMedia?, ContentEditingOperationStatus>> DeleteFromRecycleBinAsync(Guid key, Guid userKey);
|
||||
|
||||
Task<Attempt<IMedia?, ContentEditingOperationStatus>> RestoreAsync(Guid key, Guid? parentKey, Guid userKey);
|
||||
}
|
||||
|
||||
@@ -92,6 +92,9 @@ internal sealed class MediaEditingService
|
||||
public async Task<Attempt<IMedia?, ContentEditingOperationStatus>> MoveAsync(Guid key, Guid? parentKey, Guid userKey)
|
||||
=> await HandleMoveAsync(key, parentKey, userKey);
|
||||
|
||||
public async Task<Attempt<IMedia?, ContentEditingOperationStatus>> RestoreAsync(Guid key, Guid? parentKey, Guid userKey)
|
||||
=> await HandleMoveAsync(key, parentKey, userKey, true);
|
||||
|
||||
public async Task<ContentEditingOperationStatus> SortAsync(Guid? parentKey, IEnumerable<SortingModel> sortingModels, Guid userKey)
|
||||
=> await HandleSortAsync(parentKey, sortingModels, userKey);
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
|
||||
public class DocumentRecycleBinQueryService : IDocumentRecycleBinQueryService
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly ICoreScopeProvider _scopeProvider;
|
||||
private readonly IRelationService _relationService;
|
||||
|
||||
public DocumentRecycleBinQueryService(
|
||||
IEntityService entityService,
|
||||
ICoreScopeProvider scopeProvider,
|
||||
IRelationService relationService)
|
||||
{
|
||||
_entityService = entityService;
|
||||
_scopeProvider = scopeProvider;
|
||||
_relationService = relationService;
|
||||
}
|
||||
|
||||
public Task<Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>> GetOriginalParentAsync(Guid trashedDocumentId)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
|
||||
if (_entityService.Get(trashedDocumentId, UmbracoObjectTypes.Document) is not IDocumentEntitySlim entity)
|
||||
{
|
||||
return Task.FromResult(Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.NotFound));
|
||||
}
|
||||
|
||||
if (entity.Trashed is false)
|
||||
{
|
||||
return Task.FromResult(Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.NotTrashed));
|
||||
}
|
||||
|
||||
IEnumerable<IRelation> relationsByChild = _relationService.GetByChildId(entity.Id);
|
||||
IRelation? parentRecycleRelation = relationsByChild.FirstOrDefault(
|
||||
r => r.RelationType.Alias == Core.Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias);
|
||||
|
||||
if (parentRecycleRelation is null)
|
||||
{
|
||||
return Task.FromResult(Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.NoParentRecycleRelation));
|
||||
}
|
||||
|
||||
if (parentRecycleRelation.ParentId == Constants.System.Root)
|
||||
{
|
||||
return Task.FromResult(Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>.Succeed(RecycleBinQueryResultType.ParentIsRoot, null));
|
||||
}
|
||||
|
||||
var parent =
|
||||
_entityService.Get(parentRecycleRelation.ParentId, UmbracoObjectTypes.Document) as IDocumentEntitySlim;
|
||||
if (parent is null)
|
||||
{
|
||||
return Task.FromResult(Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.ParentNotFound));
|
||||
}
|
||||
|
||||
if (parent.Trashed)
|
||||
{
|
||||
return Task.FromResult(Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.ParentNotFound, parent));
|
||||
}
|
||||
|
||||
return Task.FromResult(Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>.Succeed(RecycleBinQueryResultType.Success, parent));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
|
||||
public interface IDocumentRecycleBinQueryService
|
||||
{
|
||||
Task<Attempt<IDocumentEntitySlim?, RecycleBinQueryResultType>> GetOriginalParentAsync(Guid trashedDocumentId);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
|
||||
public interface IMediaRecycleBinQueryService
|
||||
{
|
||||
Task<Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>> GetOriginalParentAsync(Guid trashedMediaId);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
|
||||
public class MediaRecycleBinQueryService : IMediaRecycleBinQueryService
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly ICoreScopeProvider _scopeProvider;
|
||||
private readonly IRelationService _relationService;
|
||||
|
||||
public MediaRecycleBinQueryService(
|
||||
IEntityService entityService,
|
||||
ICoreScopeProvider scopeProvider,
|
||||
IRelationService relationService)
|
||||
{
|
||||
_entityService = entityService;
|
||||
_scopeProvider = scopeProvider;
|
||||
_relationService = relationService;
|
||||
}
|
||||
|
||||
public Task<Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>> GetOriginalParentAsync(Guid trashedMediaId)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true);
|
||||
|
||||
if (_entityService.Get(trashedMediaId, UmbracoObjectTypes.Media) is not IMediaEntitySlim entity)
|
||||
{
|
||||
return Task.FromResult(Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.NotFound));
|
||||
}
|
||||
|
||||
if (entity.Trashed is false)
|
||||
{
|
||||
return Task.FromResult(Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.NotTrashed));
|
||||
}
|
||||
|
||||
IEnumerable<IRelation> relationsByChild = _relationService.GetByChildId(entity.Id);
|
||||
IRelation? parentRecycleRelation = relationsByChild.FirstOrDefault(
|
||||
r => r.RelationType.Alias == Core.Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias);
|
||||
|
||||
if (parentRecycleRelation is null)
|
||||
{
|
||||
return Task.FromResult(Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.NoParentRecycleRelation));
|
||||
}
|
||||
|
||||
if (parentRecycleRelation.ParentId == Constants.System.Root)
|
||||
{
|
||||
return Task.FromResult(Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>.Succeed(RecycleBinQueryResultType.ParentIsRoot, null));
|
||||
}
|
||||
|
||||
var parent =
|
||||
_entityService.Get(parentRecycleRelation.ParentId, UmbracoObjectTypes.Media) as IMediaEntitySlim;
|
||||
|
||||
if (parent is null)
|
||||
{
|
||||
return Task.FromResult(Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.ParentNotFound));
|
||||
}
|
||||
|
||||
if (parent.Trashed)
|
||||
{
|
||||
return Task.FromResult(Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>.Fail(RecycleBinQueryResultType.ParentNotFound, parent));
|
||||
}
|
||||
|
||||
return Task.FromResult(Attempt<IMediaEntitySlim?, RecycleBinQueryResultType>.Succeed(RecycleBinQueryResultType.Success, parent));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Umbraco.Cms.Core.Services.Querying.RecycleBin;
|
||||
|
||||
/// <summary>
|
||||
/// < 10 = Success
|
||||
/// </summary>
|
||||
public enum RecycleBinQueryResultType
|
||||
{
|
||||
Success = 0,
|
||||
ParentIsRoot = 2,
|
||||
NotFound = 11,
|
||||
NotTrashed = 12,
|
||||
NoParentRecycleRelation = 13,
|
||||
ParentNotFound = 14,
|
||||
ParentIsTrashed = 15,
|
||||
}
|
||||
Reference in New Issue
Block a user