Document version endpoints (#15946)
* Rename/Move/duplicate PaginationService to facilitate conversion closer to the data layer Duplication is because of internal modifier as we don't want to expose these temporary classes * Move Guid to Int Extensions into core + add unittests * Added Document version endpoints Updated used services to use async methods * Moved PaginationConverter into core so it can be used by the service layer * Endpoint structure improvements * Updating OpenApi.json * Add greedy constructors for contentService tests * Namespace changes and naming cleanup * Update openapispec again... * Refactor injected services * PR suggestion updates - Move endpoints into their own structural section as they are also in a different swagger section - Naming improvements - Allign PresentationFactories with similar classes - Cleanup unused assignments - Cleanup refactoring comments - Improve obsoletion remarks * Cleanup * ResponseModel improvements * OpenApi spec update --------- Co-authored-by: Sven Geusens <sge@umbraco.dk> Co-authored-by: Elitsa <elm@umbraco.dk>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
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.Document;
|
||||
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.DocumentVersion;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class AllDocumentVersionController : DocumentVersionControllerBase
|
||||
{
|
||||
private readonly IContentVersionService _contentVersionService;
|
||||
private readonly IDocumentVersionPresentationFactory _documentVersionPresentationFactory;
|
||||
|
||||
public AllDocumentVersionController(
|
||||
IContentVersionService contentVersionService,
|
||||
IDocumentVersionPresentationFactory documentVersionPresentationFactory)
|
||||
{
|
||||
_contentVersionService = contentVersionService;
|
||||
_documentVersionPresentationFactory = documentVersionPresentationFactory;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(PagedViewModel<DocumentVersionItemResponseModel>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> All([Required] Guid documentId, string? culture, int skip = 0, int take = 100)
|
||||
{
|
||||
Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus> attempt =
|
||||
await _contentVersionService.GetPagedContentVersionsAsync(documentId, culture, skip, take);
|
||||
|
||||
var pagedViewModel = new PagedViewModel<DocumentVersionItemResponseModel>
|
||||
{
|
||||
Total = attempt.Result!.Total,
|
||||
Items = await _documentVersionPresentationFactory.CreateMultipleAsync(attempt.Result!.Items),
|
||||
};
|
||||
|
||||
return attempt.Success
|
||||
? Ok(pagedViewModel)
|
||||
: MapFailure(attempt.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
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.DocumentVersion;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class ByKeyDocumentVersionController : DocumentVersionControllerBase
|
||||
{
|
||||
private readonly IContentVersionService _contentVersionService;
|
||||
private readonly IUmbracoMapper _umbracoMapper;
|
||||
|
||||
public ByKeyDocumentVersionController(
|
||||
IContentVersionService contentVersionService,
|
||||
IUmbracoMapper umbracoMapper)
|
||||
{
|
||||
_contentVersionService = contentVersionService;
|
||||
_umbracoMapper = umbracoMapper;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpGet("{id:guid}")]
|
||||
[ProducesResponseType(typeof(DocumentVersionResponseModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> ByKey(Guid id)
|
||||
{
|
||||
Attempt<IContent?, ContentVersionOperationStatus> attempt =
|
||||
await _contentVersionService.GetAsync(id);
|
||||
|
||||
return attempt.Success
|
||||
? Ok(_umbracoMapper.Map<DocumentVersionResponseModel>(attempt.Result))
|
||||
: MapFailure(attempt.Status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.DocumentVersion;
|
||||
|
||||
[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Document}-version")]
|
||||
[ApiExplorerSettings(GroupName = $"{nameof(Constants.UdiEntityType.Document)} Version")]
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocuments)]
|
||||
public abstract class DocumentVersionControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
protected IActionResult MapFailure(ContentVersionOperationStatus status)
|
||||
=> OperationStatusResult(status, problemDetailsBuilder => status switch
|
||||
{
|
||||
ContentVersionOperationStatus.NotFound => NotFound(problemDetailsBuilder
|
||||
.WithTitle("The requested version could not be found")
|
||||
.Build()),
|
||||
ContentVersionOperationStatus.ContentNotFound => NotFound(problemDetailsBuilder
|
||||
.WithTitle("The requested document could not be found")
|
||||
.Build()),
|
||||
ContentVersionOperationStatus.InvalidSkipTake => SkipTakeToPagingProblem(),
|
||||
ContentVersionOperationStatus.RollBackFailed => BadRequest(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
|
||||
.WithTitle("Request cancelled by notification")
|
||||
.WithDetail("The request to roll back was cancelled by a notification handler.")
|
||||
.Build()),
|
||||
_ => StatusCode(StatusCodes.Status500InternalServerError, problemDetailsBuilder
|
||||
.WithTitle("Unknown content version operation status.")
|
||||
.Build()),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.DocumentVersion;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class RollbackDocumentVersionController : DocumentVersionControllerBase
|
||||
{
|
||||
private readonly IContentVersionService _contentVersionService;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public RollbackDocumentVersionController(
|
||||
IContentVersionService contentVersionService,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_contentVersionService = contentVersionService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpPost("{id:guid}/rollback")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> Rollback(Guid id, string? culture)
|
||||
{
|
||||
Attempt<ContentVersionOperationStatus> attempt =
|
||||
await _contentVersionService.RollBackAsync(id, culture, CurrentUserKey(_backOfficeSecurityAccessor));
|
||||
|
||||
return attempt.Success
|
||||
? Ok()
|
||||
: MapFailure(attempt.Result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.DocumentVersion;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class UpdatePreventCleanupDocumentVersionController : DocumentVersionControllerBase
|
||||
{
|
||||
private readonly IContentVersionService _contentVersionService;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public UpdatePreventCleanupDocumentVersionController(
|
||||
IContentVersionService contentVersionService,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_contentVersionService = contentVersionService;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpPut("{id:guid}/prevent-cleanup")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
|
||||
public async Task<IActionResult> Set(Guid id, bool preventCleanup)
|
||||
{
|
||||
Attempt<ContentVersionOperationStatus> attempt =
|
||||
await _contentVersionService.SetPreventCleanupAsync(id, preventCleanup, CurrentUserKey(_backOfficeSecurityAccessor));
|
||||
|
||||
return attempt.Success
|
||||
? Ok()
|
||||
: MapFailure(attempt.Result);
|
||||
}
|
||||
}
|
||||
@@ -62,4 +62,13 @@ public abstract class ManagementApiControllerBase : Controller, IUmbracoFeature
|
||||
protected static IActionResult OperationStatusResult<TEnum>(TEnum status, Func<ProblemDetailsBuilder, IActionResult> result)
|
||||
where TEnum : Enum
|
||||
=> result(new ProblemDetailsBuilder().WithOperationStatus(status));
|
||||
|
||||
protected BadRequestObjectResult SkipTakeToPagingProblem() =>
|
||||
BadRequest(new ProblemDetails
|
||||
{
|
||||
Title = "Invalid skip/take",
|
||||
Detail = "Skip must be a multiple of take - i.e. skip = 10, take = 5",
|
||||
Status = StatusCodes.Status400BadRequest,
|
||||
Type = "Error",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,10 +16,12 @@ internal static class DocumentBuilderExtensions
|
||||
builder.Services.AddTransient<IDocumentEditingPresentationFactory, DocumentEditingPresentationFactory>();
|
||||
builder.Services.AddTransient<IPublicAccessPresentationFactory, PublicAccessPresentationFactory>();
|
||||
builder.Services.AddTransient<IDomainPresentationFactory, DomainPresentationFactory>();
|
||||
builder.Services.AddTransient<IDocumentVersionPresentationFactory, DocumentVersionPresentationFactory>();
|
||||
|
||||
builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>()
|
||||
.Add<DocumentMapDefinition>()
|
||||
.Add<DomainMapDefinition>();
|
||||
.Add<DomainMapDefinition>()
|
||||
.Add<DocumentVersionMapDefinition>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
internal sealed class DocumentVersionPresentationFactory : IDocumentVersionPresentationFactory
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IUserIdKeyResolver _userIdKeyResolver;
|
||||
|
||||
public DocumentVersionPresentationFactory(
|
||||
IEntityService entityService,
|
||||
IUserIdKeyResolver userIdKeyResolver)
|
||||
{
|
||||
_entityService = entityService;
|
||||
_userIdKeyResolver = userIdKeyResolver;
|
||||
}
|
||||
|
||||
public async Task<DocumentVersionItemResponseModel> CreateAsync(ContentVersionMeta contentVersion) =>
|
||||
new(
|
||||
contentVersion.VersionId.ToGuid(), // this is a magic guid since versions do not have keys in the DB
|
||||
new ReferenceByIdModel(_entityService.GetKey(contentVersion.ContentId, UmbracoObjectTypes.Document).Result),
|
||||
new ReferenceByIdModel(_entityService.GetKey(contentVersion.ContentTypeId, UmbracoObjectTypes.DocumentType)
|
||||
.Result),
|
||||
new ReferenceByIdModel(await _userIdKeyResolver.GetAsync(contentVersion.UserId)),
|
||||
new DateTimeOffset(contentVersion.VersionDate, TimeSpan.Zero), // todo align with datetime offset rework
|
||||
contentVersion.CurrentPublishedVersion,
|
||||
contentVersion.CurrentDraftVersion,
|
||||
contentVersion.PreventCleanup);
|
||||
|
||||
public async Task<IEnumerable<DocumentVersionItemResponseModel>> CreateMultipleAsync(IEnumerable<ContentVersionMeta> contentVersions) =>
|
||||
await Task.WhenAll(contentVersions.Select(CreateAsync));
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public interface IDocumentVersionPresentationFactory
|
||||
{
|
||||
Task<DocumentVersionItemResponseModel> CreateAsync(ContentVersionMeta contentVersion);
|
||||
|
||||
Task<IEnumerable<DocumentVersionItemResponseModel>> CreateMultipleAsync(
|
||||
IEnumerable<ContentVersionMeta> contentVersions);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Umbraco.Cms.Api.Management.Mapping.Content;
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Mapping.Document;
|
||||
|
||||
public class DocumentVersionMapDefinition : ContentMapDefinition<IContent, DocumentValueModel, DocumentVariantResponseModel>, IMapDefinition
|
||||
{
|
||||
public DocumentVersionMapDefinition(PropertyEditorCollection propertyEditorCollection)
|
||||
: base(propertyEditorCollection)
|
||||
{
|
||||
}
|
||||
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
{
|
||||
mapper.Define<IContent, DocumentVersionResponseModel>((_, _) => new DocumentVersionResponseModel(), Map);
|
||||
}
|
||||
|
||||
private void Map(IContent source, DocumentVersionResponseModel target, MapperContext context)
|
||||
{
|
||||
target.Id = source.VersionId.ToGuid(); // this is a magic guid since versions do not have Guids in the DB
|
||||
target.Document = new ReferenceByIdModel(source.Key);
|
||||
target.DocumentType = context.Map<DocumentTypeReferenceResponseModel>(source.ContentType)!;
|
||||
target.Values = MapValueViewModels(source.Properties);
|
||||
target.Variants = MapVariantViewModels(
|
||||
source,
|
||||
(culture, _, documentVariantViewModel) =>
|
||||
{
|
||||
documentVariantViewModel.State = DocumentVariantStateHelper.GetState(source, culture);
|
||||
documentVariantViewModel.PublishDate = culture == null
|
||||
? source.PublishDate
|
||||
: source.GetPublishDate(culture);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -5446,6 +5446,451 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/document-version": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Document Version"
|
||||
],
|
||||
"operationId": "GetDocumentVersion",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "documentId",
|
||||
"in": "query",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "culture",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedDocumentVersionItemResponseModel"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedDocumentVersionItemResponseModel"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedDocumentVersionItemResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/document-version/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Document Version"
|
||||
],
|
||||
"operationId": "GetDocumentVersionById",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVersionResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVersionResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVersionResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/document-version/{id}/prevent-cleanup": {
|
||||
"put": {
|
||||
"tags": [
|
||||
"Document Version"
|
||||
],
|
||||
"operationId": "PutDocumentVersionByIdPreventCleanup",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "preventCleanup",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"headers": {
|
||||
"Umb-Notifications": {
|
||||
"description": "The list of notifications produced during the request.",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/NotificationHeaderModel"
|
||||
},
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"headers": {
|
||||
"Umb-Notifications": {
|
||||
"description": "The list of notifications produced during the request.",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/NotificationHeaderModel"
|
||||
},
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"headers": {
|
||||
"Umb-Notifications": {
|
||||
"description": "The list of notifications produced during the request.",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/NotificationHeaderModel"
|
||||
},
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/document-version/{id}/rollback": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Document Version"
|
||||
],
|
||||
"operationId": "PostDocumentVersionByIdRollback",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "culture",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"headers": {
|
||||
"Umb-Notifications": {
|
||||
"description": "The list of notifications produced during the request.",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/NotificationHeaderModel"
|
||||
},
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"headers": {
|
||||
"Umb-Notifications": {
|
||||
"description": "The list of notifications produced during the request.",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/NotificationHeaderModel"
|
||||
},
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"headers": {
|
||||
"Umb-Notifications": {
|
||||
"description": "The list of notifications produced during the request.",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/NotificationHeaderModel"
|
||||
},
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/collection/document/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -36214,6 +36659,89 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"DocumentVersionItemResponseModel": {
|
||||
"required": [
|
||||
"document",
|
||||
"documentType",
|
||||
"id",
|
||||
"isCurrentDraftVersion",
|
||||
"isCurrentPublishedVersion",
|
||||
"preventCleanup",
|
||||
"user",
|
||||
"versionDate"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"document": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ReferenceByIdModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"documentType": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ReferenceByIdModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ReferenceByIdModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"versionDate": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"isCurrentPublishedVersion": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isCurrentDraftVersion": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"preventCleanup": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"DocumentVersionResponseModel": {
|
||||
"required": [
|
||||
"documentType"
|
||||
],
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ContentForDocumentResponseModel"
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"document": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ReferenceByIdModel"
|
||||
}
|
||||
],
|
||||
"nullable": true
|
||||
},
|
||||
"documentType": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypeReferenceResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"DomainPresentationModel": {
|
||||
"required": [
|
||||
"domainName",
|
||||
@@ -38891,6 +39419,30 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedDocumentVersionItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"total"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentVersionItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedFileSystemTreeItemPresentationModel": {
|
||||
"required": [
|
||||
"items",
|
||||
@@ -43030,4 +43582,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
|
||||
public class DocumentVersionItemResponseModel
|
||||
{
|
||||
public DocumentVersionItemResponseModel(
|
||||
Guid id,
|
||||
ReferenceByIdModel document,
|
||||
ReferenceByIdModel documentType,
|
||||
ReferenceByIdModel user,
|
||||
DateTimeOffset versionDate,
|
||||
bool isCurrentPublishedVersion,
|
||||
bool isCurrentDraftVersion,
|
||||
bool preventCleanup)
|
||||
{
|
||||
Id = id;
|
||||
Document = document;
|
||||
DocumentType = documentType;
|
||||
|
||||
User = user;
|
||||
VersionDate = versionDate;
|
||||
IsCurrentPublishedVersion = isCurrentPublishedVersion;
|
||||
IsCurrentDraftVersion = isCurrentDraftVersion;
|
||||
PreventCleanup = preventCleanup;
|
||||
}
|
||||
|
||||
public Guid Id { get; }
|
||||
|
||||
public ReferenceByIdModel Document { get; }
|
||||
|
||||
public ReferenceByIdModel DocumentType { get; }
|
||||
|
||||
public ReferenceByIdModel User { get; }
|
||||
|
||||
public DateTimeOffset VersionDate { get; }
|
||||
|
||||
public bool IsCurrentPublishedVersion { get; }
|
||||
|
||||
public bool IsCurrentDraftVersion { get; }
|
||||
|
||||
public bool PreventCleanup { get; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Content;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
|
||||
public class DocumentVersionResponseModel : ContentResponseModelBase<DocumentValueModel, DocumentVariantResponseModel>
|
||||
{
|
||||
public ReferenceByIdModel? Document { get; set; }
|
||||
|
||||
public DocumentTypeReferenceResponseModel DocumentType { get; set; } = new();
|
||||
}
|
||||
@@ -1,22 +1,17 @@
|
||||
namespace Umbraco.Cms.Infrastructure.Extensions;
|
||||
namespace Umbraco.Cms.Core.Extensions;
|
||||
|
||||
public static class GuidExtensions
|
||||
{
|
||||
internal static bool IsFakeGuid(this Guid guid)
|
||||
public static bool IsFakeGuid(this Guid guid)
|
||||
{
|
||||
var bytes = guid.ToByteArray();
|
||||
|
||||
// Our fake guid is a 32 bit int, converted to a byte representation,
|
||||
// so we can check if everything but the first 4 bytes are 0, if so, we know it's a fake guid.
|
||||
if (bytes[4..].All(x => x == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return bytes[4..].All(x => x == 0);
|
||||
}
|
||||
|
||||
internal static int ToInt(this Guid guid)
|
||||
public static int ToInt(this Guid guid)
|
||||
{
|
||||
var bytes = guid.ToByteArray();
|
||||
return BitConverter.ToInt32(bytes, 0);
|
||||
@@ -1,9 +1,15 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Extensions;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Core.Services.Pagination;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
@@ -16,9 +22,37 @@ internal class ContentVersionService : IContentVersionService
|
||||
private readonly IDocumentVersionRepository _documentVersionRepository;
|
||||
private readonly IEventMessagesFactory _eventMessagesFactory;
|
||||
private readonly ILanguageRepository _languageRepository;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IUserIdKeyResolver _userIdKeyResolver;
|
||||
private readonly ILogger<ContentVersionService> _logger;
|
||||
private readonly ICoreScopeProvider _scopeProvider;
|
||||
|
||||
public ContentVersionService(
|
||||
ILogger<ContentVersionService> logger,
|
||||
IDocumentVersionRepository documentVersionRepository,
|
||||
IContentVersionCleanupPolicy contentVersionCleanupPolicy,
|
||||
ICoreScopeProvider scopeProvider,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IAuditRepository auditRepository,
|
||||
ILanguageRepository languageRepository,
|
||||
IEntityService entityService,
|
||||
IContentService contentService,
|
||||
IUserIdKeyResolver userIdKeyResolver)
|
||||
{
|
||||
_logger = logger;
|
||||
_documentVersionRepository = documentVersionRepository;
|
||||
_contentVersionCleanupPolicy = contentVersionCleanupPolicy;
|
||||
_scopeProvider = scopeProvider;
|
||||
_eventMessagesFactory = eventMessagesFactory;
|
||||
_auditRepository = auditRepository;
|
||||
_languageRepository = languageRepository;
|
||||
_entityService = entityService;
|
||||
_contentService = contentService;
|
||||
_userIdKeyResolver = userIdKeyResolver;
|
||||
}
|
||||
|
||||
[Obsolete("Use the non obsolete constructor instead. Scheduled to be removed in v15")]
|
||||
public ContentVersionService(
|
||||
ILogger<ContentVersionService> logger,
|
||||
IDocumentVersionRepository documentVersionRepository,
|
||||
@@ -35,6 +69,9 @@ internal class ContentVersionService : IContentVersionService
|
||||
_eventMessagesFactory = eventMessagesFactory;
|
||||
_auditRepository = auditRepository;
|
||||
_languageRepository = languageRepository;
|
||||
_entityService = StaticServiceProvider.Instance.GetRequiredService<IEntityService>();
|
||||
_contentService = StaticServiceProvider.Instance.GetRequiredService<IContentService>();
|
||||
_userIdKeyResolver = StaticServiceProvider.Instance.GetRequiredService<IUserIdKeyResolver>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -45,6 +82,7 @@ internal class ContentVersionService : IContentVersionService
|
||||
CleanupDocumentVersions(asAtDate);
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("Use the async version instead. Scheduled to be removed in v15")]
|
||||
public IEnumerable<ContentVersionMeta>? GetPagedContentVersions(int contentId, long pageIndex, int pageSize, out long totalRecords, string? culture = null)
|
||||
{
|
||||
if (pageIndex < 0)
|
||||
@@ -57,6 +95,113 @@ internal class ContentVersionService : IContentVersionService
|
||||
throw new ArgumentOutOfRangeException(nameof(pageSize));
|
||||
}
|
||||
|
||||
return HandleGetPagedContentVersions(contentId, pageIndex, pageSize, out totalRecords, culture);
|
||||
}
|
||||
|
||||
public ContentVersionMeta? Get(int versionId)
|
||||
{
|
||||
using (ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
scope.ReadLock(Constants.Locks.ContentTree);
|
||||
return _documentVersionRepository.Get(versionId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[Obsolete("Use the async version instead. Scheduled to be removed in v15")]
|
||||
public void SetPreventCleanup(int versionId, bool preventCleanup, int userId = Constants.Security.SuperUserId)
|
||||
=> HandleSetPreventCleanup(versionId, preventCleanup, userId);
|
||||
|
||||
public async Task<Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus>> GetPagedContentVersionsAsync(Guid contentId, string? culture, int skip, int take)
|
||||
{
|
||||
IEntitySlim? document = await Task.FromResult(_entityService.Get(contentId, UmbracoObjectTypes.Document));
|
||||
if (document is null)
|
||||
{
|
||||
return Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus.ContentNotFound);
|
||||
}
|
||||
|
||||
if (PaginationConverter.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize) == false)
|
||||
{
|
||||
return Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus.InvalidSkipTake);
|
||||
}
|
||||
|
||||
IEnumerable<ContentVersionMeta>? versions =
|
||||
await Task.FromResult(HandleGetPagedContentVersions(
|
||||
document.Id,
|
||||
pageNumber,
|
||||
pageSize,
|
||||
out var total,
|
||||
culture));
|
||||
|
||||
if (versions is null)
|
||||
{
|
||||
return Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus.NotFound);
|
||||
}
|
||||
|
||||
return Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus>.Succeed(
|
||||
ContentVersionOperationStatus.Success, new PagedModel<ContentVersionMeta>(total, versions));
|
||||
}
|
||||
|
||||
public async Task<Attempt<IContent?, ContentVersionOperationStatus>> GetAsync(Guid versionId)
|
||||
{
|
||||
IContent? version = await Task.FromResult(_contentService.GetVersion(versionId.ToInt()));
|
||||
if (version is null)
|
||||
{
|
||||
return Attempt<IContent?, ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus
|
||||
.NotFound);
|
||||
}
|
||||
|
||||
return Attempt<IContent?, ContentVersionOperationStatus>.Succeed(ContentVersionOperationStatus.Success, version);
|
||||
}
|
||||
|
||||
public async Task<Attempt<ContentVersionOperationStatus>> SetPreventCleanupAsync(Guid versionId, bool preventCleanup, Guid userKey)
|
||||
{
|
||||
ContentVersionMeta? version = Get(versionId.ToInt());
|
||||
if (version is null)
|
||||
{
|
||||
return Attempt<ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus.NotFound);
|
||||
}
|
||||
|
||||
HandleSetPreventCleanup(version.VersionId, preventCleanup, await _userIdKeyResolver.GetAsync(userKey));
|
||||
|
||||
return Attempt<ContentVersionOperationStatus>.Succeed(ContentVersionOperationStatus.Success);
|
||||
}
|
||||
|
||||
public async Task<Attempt<ContentVersionOperationStatus>> RollBackAsync(Guid versionId, string? culture, Guid userKey)
|
||||
{
|
||||
ContentVersionMeta? version = Get(versionId.ToInt());
|
||||
if (version is null)
|
||||
{
|
||||
return Attempt<ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus.NotFound);
|
||||
}
|
||||
|
||||
OperationResult rollBackResult = _contentService.Rollback(
|
||||
version.ContentId,
|
||||
version.VersionId,
|
||||
culture ?? "*",
|
||||
await _userIdKeyResolver.GetAsync(userKey));
|
||||
|
||||
if (rollBackResult.Success)
|
||||
{
|
||||
return Attempt<ContentVersionOperationStatus>.Succeed(ContentVersionOperationStatus.Success);
|
||||
}
|
||||
|
||||
switch (rollBackResult.Result)
|
||||
{
|
||||
case OperationResultType.Failed:
|
||||
case OperationResultType.FailedCannot:
|
||||
case OperationResultType.FailedExceptionThrown:
|
||||
case OperationResultType.NoOperation:
|
||||
default:
|
||||
return Attempt<ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus.RollBackFailed);
|
||||
case OperationResultType.FailedCancelledByEvent:
|
||||
return Attempt<ContentVersionOperationStatus>.Fail(ContentVersionOperationStatus.RollBackCanceled);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ContentVersionMeta>? HandleGetPagedContentVersions(int contentId, long pageIndex,
|
||||
int pageSize, out long totalRecords, string? culture = null)
|
||||
{
|
||||
using (ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
var languageId = _languageRepository.GetIdByIsoCode(culture, true);
|
||||
@@ -65,8 +210,7 @@ internal class ContentVersionService : IContentVersionService
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetPreventCleanup(int versionId, bool preventCleanup, int userId = Constants.Security.SuperUserId)
|
||||
private void HandleSetPreventCleanup(int versionId, bool preventCleanup, int userId)
|
||||
{
|
||||
using (ICoreScope scope = _scopeProvider.CreateCoreScope())
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -13,10 +14,19 @@ public interface IContentVersionService
|
||||
/// Gets paginated content versions for given content id paginated.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentException">Thrown when <paramref name="culture" /> is invalid.</exception>
|
||||
[Obsolete("Use the async version instead. Scheduled to be removed in v15")]
|
||||
IEnumerable<ContentVersionMeta>? GetPagedContentVersions(int contentId, long pageIndex, int pageSize, out long totalRecords, string? culture = null);
|
||||
|
||||
/// <summary>
|
||||
/// Updates preventCleanup value for given content version.
|
||||
/// </summary>
|
||||
[Obsolete("Use the async version instead. Scheduled to be removed in v15")]
|
||||
void SetPreventCleanup(int versionId, bool preventCleanup, int userId = -1);
|
||||
|
||||
ContentVersionMeta? Get(int versionId);
|
||||
Task<Attempt<PagedModel<ContentVersionMeta>?, ContentVersionOperationStatus>> GetPagedContentVersionsAsync(Guid contentId, string? culture, int skip, int take);
|
||||
Task<Attempt<IContent?, ContentVersionOperationStatus>> GetAsync(Guid versionId);
|
||||
|
||||
Task<Attempt<ContentVersionOperationStatus>> SetPreventCleanupAsync(Guid versionId, bool preventCleanup, Guid userKey);
|
||||
Task<Attempt<ContentVersionOperationStatus>> RollBackAsync(Guid versionId, string? culture, Guid userKey);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
public enum ContentVersionOperationStatus
|
||||
{
|
||||
Success,
|
||||
NotFound,
|
||||
ContentNotFound,
|
||||
InvalidSkipTake,
|
||||
RollBackFailed,
|
||||
RollBackCanceled
|
||||
}
|
||||
23
src/Umbraco.Core/Services/Pagination/PaginationConverter.cs
Normal file
23
src/Umbraco.Core/Services/Pagination/PaginationConverter.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Umbraco.Cms.Core.Services.Pagination;
|
||||
|
||||
internal static class PaginationConverter
|
||||
{
|
||||
internal static bool ConvertSkipTakeToPaging(int skip, int take, out long pageNumber, out int pageSize)
|
||||
{
|
||||
if (take < 0)
|
||||
{
|
||||
throw new ArgumentException("Must be equal to or greater than zero", nameof(take));
|
||||
}
|
||||
|
||||
if (take != 0 && skip % take != 0)
|
||||
{
|
||||
pageSize = 0;
|
||||
pageNumber = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
pageSize = take;
|
||||
pageNumber = take == 0 ? 0 : skip / take;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Umbraco.Cms.Infrastructure.Extensions;
|
||||
using Umbraco.Cms.Core.Extensions;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Security;
|
||||
|
||||
@@ -33,7 +33,8 @@ internal class UmbracoCustomizations : ICustomization
|
||||
.Customize(new ConstructorCustomization(typeof(MemberManager), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(DatabaseSchemaCreatorFactory), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(InstallHelper), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(DatabaseBuilder), new GreedyConstructorQuery()));
|
||||
.Customize(new ConstructorCustomization(typeof(DatabaseBuilder), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(ContentVersionService), new GreedyConstructorQuery()));
|
||||
|
||||
// When requesting an IUserStore ensure we actually uses a IUserLockoutStore
|
||||
fixture.Customize<IUserStore<BackOfficeIdentityUser>>(cc =>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Extensions;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Extensions;
|
||||
|
||||
[TestFixture]
|
||||
public class IntGuidIntConversionTests
|
||||
{
|
||||
[TestCase(int.MinValue)]
|
||||
[TestCase(int.MaxValue)]
|
||||
[TestCase(int.MinValue / 2)]
|
||||
[TestCase(int.MinValue / 5)]
|
||||
[TestCase(int.MinValue / 707)]
|
||||
[TestCase(int.MinValue / 1313)]
|
||||
[TestCase(int.MinValue / 17017)]
|
||||
[TestCase(int.MaxValue / 2)]
|
||||
[TestCase(int.MaxValue / 5)]
|
||||
[TestCase(int.MaxValue / 707)]
|
||||
[TestCase(int.MaxValue / 1313)]
|
||||
[TestCase(int.MaxValue / 17017)]
|
||||
public void IntoToGuidToInt_NoChange(int startValue)
|
||||
{
|
||||
var intermediateValue = startValue.ToGuid();
|
||||
var endValue = intermediateValue.ToInt();
|
||||
|
||||
Assert.AreEqual(startValue, endValue);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user