Retrieves item counts before and after the target for sibling endpoints and returns in API response (#19844)
* Added user start node restrictions to sibling endpoints. * Further integration tests. * Tidy up. * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Revert previous update. * Retrieves item counts before and after the target for sibling endpoints and returns in API response. * Applied previous update correctly. * Removed blank line. * Fix build and test asserts following merge. * Update OpenApi.json. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: mole <nikolajlauridsen@protonmail.ch>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
|
||||
public class SubsetViewModel<T>
|
||||
{
|
||||
[Required]
|
||||
public long TotalBefore { get; set; }
|
||||
|
||||
[Required]
|
||||
public long TotalAfter { get; set; }
|
||||
|
||||
[Required]
|
||||
public IEnumerable<T> Items { get; set; } = Enumerable.Empty<T>();
|
||||
|
||||
public static SubsetViewModel<T> Empty() => new();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -13,7 +14,7 @@ public class SiblingsDataTypeTreeController : DataTypeTreeControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("siblings")]
|
||||
[ProducesResponseType(typeof(IEnumerable<DataTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<IEnumerable<DataTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
|
||||
[ProducesResponseType(typeof(SubsetViewModel<DataTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<SubsetViewModel<DataTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
|
||||
=> GetSiblings(target, before, after);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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.Services.Entities;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
@@ -34,8 +35,8 @@ public class SiblingsDocumentTreeController : DocumentTreeControllerBase
|
||||
|
||||
[HttpGet("siblings")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(IEnumerable<DocumentTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<IEnumerable<DocumentTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
|
||||
[ProducesResponseType(typeof(SubsetViewModel<DocumentTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<SubsetViewModel<DocumentTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
|
||||
{
|
||||
IgnoreUserStartNodesForDataType(dataTypeId);
|
||||
return GetSiblings(target, before, after);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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.Tree;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
@@ -14,8 +15,8 @@ public class SiblingsDocumentBlueprintTreeController : DocumentBlueprintTreeCont
|
||||
}
|
||||
|
||||
[HttpGet("siblings")]
|
||||
[ProducesResponseType(typeof(IEnumerable<DocumentBlueprintTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<IEnumerable<DocumentBlueprintTreeItemResponseModel>>> Siblings(
|
||||
[ProducesResponseType(typeof(SubsetViewModel<DocumentBlueprintTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<SubsetViewModel<DocumentBlueprintTreeItemResponseModel>>> Siblings(
|
||||
CancellationToken cancellationToken,
|
||||
Guid target,
|
||||
int before,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -13,8 +14,8 @@ public class SiblingsDocumentTypeTreeController : DocumentTypeTreeControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("siblings")]
|
||||
[ProducesResponseType(typeof(IEnumerable<DocumentTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<IEnumerable<DocumentTypeTreeItemResponseModel>>> Siblings(
|
||||
[ProducesResponseType(typeof(SubsetViewModel<DocumentTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<SubsetViewModel<DocumentTypeTreeItemResponseModel>>> Siblings(
|
||||
CancellationToken cancellationToken,
|
||||
Guid target,
|
||||
int before,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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.Services.Entities;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
@@ -23,8 +24,8 @@ public class SiblingsMediaTreeController : MediaTreeControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("siblings")]
|
||||
[ProducesResponseType(typeof(IEnumerable<MediaTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<IEnumerable<MediaTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
|
||||
[ProducesResponseType(typeof(SubsetViewModel<MediaTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<SubsetViewModel<MediaTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
|
||||
{
|
||||
IgnoreUserStartNodesForDataType(dataTypeId);
|
||||
return GetSiblings(target, before, after);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -13,7 +14,7 @@ public class SiblingsMediaTypeTreeController : MediaTypeTreeControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("siblings")]
|
||||
[ProducesResponseType(typeof(IEnumerable<MediaTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<IEnumerable<MediaTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
|
||||
[ProducesResponseType(typeof(SubsetViewModel<MediaTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<SubsetViewModel<MediaTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
|
||||
=> GetSiblings(target, before, after);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Tree;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -13,8 +14,8 @@ public class SiblingsTemplateTreeController : TemplateTreeControllerBase
|
||||
}
|
||||
|
||||
[HttpGet("siblings")]
|
||||
[ProducesResponseType(typeof(IEnumerable<NamedEntityTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<IEnumerable<NamedEntityTreeItemResponseModel>>> Siblings(
|
||||
[ProducesResponseType(typeof(SubsetViewModel<NamedEntityTreeItemResponseModel>), StatusCodes.Status200OK)]
|
||||
public Task<ActionResult<SubsetViewModel<NamedEntityTreeItemResponseModel>>> Siblings(
|
||||
CancellationToken cancellationToken,
|
||||
Guid target,
|
||||
int before,
|
||||
|
||||
@@ -44,12 +44,12 @@ public abstract class EntityTreeControllerBase<TItem> : ManagementApiControllerB
|
||||
return Task.FromResult<ActionResult<PagedViewModel<TItem>>>(Ok(result));
|
||||
}
|
||||
|
||||
protected Task<ActionResult<IEnumerable<TItem>>> GetSiblings(Guid target, int before, int after)
|
||||
protected Task<ActionResult<SubsetViewModel<TItem>>> GetSiblings(Guid target, int before, int after)
|
||||
{
|
||||
IEntitySlim[] siblings = GetSiblingEntities(target, before, after);
|
||||
IEntitySlim[] siblings = GetSiblingEntities(target, before, after, out var totalBefore, out var totalAfter);
|
||||
if (siblings.Length == 0)
|
||||
{
|
||||
return Task.FromResult<ActionResult<IEnumerable<TItem>>>(NotFound());
|
||||
return Task.FromResult<ActionResult<SubsetViewModel<TItem>>>(NotFound());
|
||||
}
|
||||
|
||||
IEntitySlim? entity = siblings.FirstOrDefault();
|
||||
@@ -57,8 +57,11 @@ public abstract class EntityTreeControllerBase<TItem> : ManagementApiControllerB
|
||||
? EntityService.GetKey(entity.ParentId, ItemObjectType).Result
|
||||
: Constants.System.RootKey;
|
||||
|
||||
TItem[] treeItemsViewModels = MapTreeItemViewModels(parentKey, siblings);
|
||||
return Task.FromResult<ActionResult<IEnumerable<TItem>>>(Ok(treeItemsViewModels));
|
||||
TItem[] treeItemViewModels = MapTreeItemViewModels(parentKey, siblings);
|
||||
|
||||
SubsetViewModel<TItem> result = SubsetViewModel(treeItemViewModels, totalBefore, totalAfter);
|
||||
|
||||
return Task.FromResult<ActionResult<SubsetViewModel<TItem>>>(Ok(result));
|
||||
}
|
||||
|
||||
protected virtual async Task<ActionResult<IEnumerable<TItem>>> GetAncestors(Guid descendantKey, bool includeSelf = true)
|
||||
@@ -120,13 +123,15 @@ public abstract class EntityTreeControllerBase<TItem> : ManagementApiControllerB
|
||||
ordering: ItemOrdering)
|
||||
.ToArray();
|
||||
|
||||
protected virtual IEntitySlim[] GetSiblingEntities(Guid target, int before, int after) =>
|
||||
protected virtual IEntitySlim[] GetSiblingEntities(Guid target, int before, int after, out long totalBefore, out long totalAfter) =>
|
||||
EntityService
|
||||
.GetSiblings(
|
||||
target,
|
||||
ItemObjectType,
|
||||
before,
|
||||
after,
|
||||
out totalBefore,
|
||||
out totalAfter,
|
||||
ordering: ItemOrdering)
|
||||
.ToArray();
|
||||
|
||||
@@ -152,4 +157,7 @@ public abstract class EntityTreeControllerBase<TItem> : ManagementApiControllerB
|
||||
|
||||
protected PagedViewModel<TItem> PagedViewModel(IEnumerable<TItem> treeItemViewModels, long totalItems)
|
||||
=> new() { Total = totalItems, Items = treeItemViewModels };
|
||||
|
||||
protected SubsetViewModel<TItem> SubsetViewModel(IEnumerable<TItem> treeItemViewModels, long totalBefore, long totalAfter)
|
||||
=> new() { TotalBefore = totalBefore, TotalAfter = totalAfter, Items = treeItemViewModels };
|
||||
}
|
||||
|
||||
@@ -59,11 +59,11 @@ public abstract class UserStartNodeTreeControllerBase<TItem> : EntityTreeControl
|
||||
return CalculateAccessMap(() => userAccessEntities, out _);
|
||||
}
|
||||
|
||||
protected override IEntitySlim[] GetSiblingEntities(Guid target, int before, int after)
|
||||
protected override IEntitySlim[] GetSiblingEntities(Guid target, int before, int after, out long totalBefore, out long totalAfter)
|
||||
{
|
||||
if (UserHasRootAccess() || IgnoreUserStartNodes())
|
||||
{
|
||||
return base.GetSiblingEntities(target, before, after);
|
||||
return base.GetSiblingEntities(target, before, after, out totalBefore, out totalAfter);
|
||||
}
|
||||
|
||||
IEnumerable<UserAccessEntity> userAccessEntities = _userStartNodeEntitiesService.SiblingUserAccessEntities(
|
||||
@@ -72,7 +72,9 @@ public abstract class UserStartNodeTreeControllerBase<TItem> : EntityTreeControl
|
||||
target,
|
||||
before,
|
||||
after,
|
||||
ItemOrdering);
|
||||
ItemOrdering,
|
||||
out totalBefore,
|
||||
out totalAfter);
|
||||
|
||||
return CalculateAccessMap(() => userAccessEntities, out _);
|
||||
}
|
||||
|
||||
@@ -1839,14 +1839,11 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DataTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SubsetDataTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4453,14 +4450,11 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentBlueprintTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SubsetDocumentBlueprintTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6770,14 +6764,11 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SubsetDocumentTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11208,6 +11199,14 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dataTypeId",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -11216,14 +11215,11 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SubsetDocumentTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16028,14 +16024,11 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SubsetMediaTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18550,6 +18543,14 @@
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dataTypeId",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -18558,14 +18559,11 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SubsetMediaTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28769,14 +28767,11 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/NamedEntityTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/SubsetNamedEntityTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36735,6 +36730,9 @@
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentPropertyValuePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownTypePermissionPresentationModel"
|
||||
}
|
||||
@@ -37021,6 +37019,9 @@
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentPropertyValuePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownTypePermissionPresentationModel"
|
||||
}
|
||||
@@ -38357,6 +38358,36 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"DocumentTypePermissionPresentationModel": {
|
||||
"required": [
|
||||
"$type",
|
||||
"documentTypeAlias",
|
||||
"verbs"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"$type": {
|
||||
"type": "string"
|
||||
},
|
||||
"verbs": {
|
||||
"uniqueItems": true,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"documentTypeAlias": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"discriminator": {
|
||||
"propertyName": "$type",
|
||||
"mapping": {
|
||||
"DocumentTypePermissionPresentationModel": "#/components/schemas/DocumentTypePermissionPresentationModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DocumentTypePropertyTypeContainerResponseModel": {
|
||||
"required": [
|
||||
"id",
|
||||
@@ -44776,6 +44807,209 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubsetDataTypeTreeItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"totalAfter",
|
||||
"totalBefore"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalBefore": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"totalAfter": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DataTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubsetDocumentBlueprintTreeItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"totalAfter",
|
||||
"totalBefore"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalBefore": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"totalAfter": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentBlueprintTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubsetDocumentTreeItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"totalAfter",
|
||||
"totalBefore"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalBefore": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"totalAfter": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubsetDocumentTypeTreeItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"totalAfter",
|
||||
"totalBefore"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalBefore": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"totalAfter": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubsetMediaTreeItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"totalAfter",
|
||||
"totalBefore"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalBefore": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"totalAfter": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubsetMediaTypeTreeItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"totalAfter",
|
||||
"totalBefore"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalBefore": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"totalAfter": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MediaTypeTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SubsetNamedEntityTreeItemResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"totalAfter",
|
||||
"totalBefore"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalBefore": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"totalAfter": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/NamedEntityTreeItemResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"TagResponseModel": {
|
||||
"required": [
|
||||
"id",
|
||||
@@ -46514,6 +46748,9 @@
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentPropertyValuePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownTypePermissionPresentationModel"
|
||||
}
|
||||
@@ -46940,6 +47177,9 @@
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentPropertyValuePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/DocumentTypePermissionPresentationModel"
|
||||
},
|
||||
{
|
||||
"$ref": "#/components/schemas/UnknownTypePermissionPresentationModel"
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ public interface IUserStartNodeEntitiesService
|
||||
/// <param name="before">The number of applicable siblings to retrieve before the target.</param>
|
||||
/// <param name="after">The number of applicable siblings to retrieve after the target.</param>
|
||||
/// <param name="ordering">The ordering to apply when fetching and paginating the children.</param>
|
||||
/// <param name="totalBefore">Outputs the total number of siblings before the target entity.</param>
|
||||
/// <param name="totalAfter">Outputs the total number of siblings after the target entity.</param>
|
||||
/// <returns>A list of sibling entities applicable for the user.</returns>
|
||||
/// <remarks>
|
||||
/// The returned entities may include entities that outside of the user start node scope, but are needed to
|
||||
@@ -84,7 +86,14 @@ public interface IUserStartNodeEntitiesService
|
||||
Guid targetKey,
|
||||
int before,
|
||||
int after,
|
||||
Ordering ordering) => [];
|
||||
Ordering ordering,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
{
|
||||
totalBefore = 0;
|
||||
totalAfter = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the access level of a collection of entities for users without root access.
|
||||
|
||||
@@ -64,7 +64,14 @@ public class UserStartNodeEntitiesService : IUserStartNodeEntitiesService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<UserAccessEntity> ChildUserAccessEntities(UmbracoObjectTypes umbracoObjectType, string[] userStartNodePaths, Guid parentKey, int skip, int take, Ordering ordering, out long totalItems)
|
||||
public IEnumerable<UserAccessEntity> ChildUserAccessEntities(
|
||||
UmbracoObjectTypes umbracoObjectType,
|
||||
string[] userStartNodePaths,
|
||||
Guid parentKey,
|
||||
int skip,
|
||||
int take,
|
||||
Ordering ordering,
|
||||
out long totalItems)
|
||||
{
|
||||
Attempt<int> parentIdAttempt = _idKeyMap.GetIdForKey(parentKey, umbracoObjectType);
|
||||
if (parentIdAttempt.Success is false)
|
||||
@@ -142,11 +149,22 @@ public class UserStartNodeEntitiesService : IUserStartNodeEntitiesService
|
||||
}).WhereNotNull().ToArray();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<UserAccessEntity> SiblingUserAccessEntities(UmbracoObjectTypes umbracoObjectType, string[] userStartNodePaths, Guid targetKey, int before, int after, Ordering ordering)
|
||||
public IEnumerable<UserAccessEntity> SiblingUserAccessEntities(
|
||||
UmbracoObjectTypes umbracoObjectType,
|
||||
string[] userStartNodePaths,
|
||||
Guid targetKey,
|
||||
int before,
|
||||
int after,
|
||||
Ordering ordering,
|
||||
out long totalBefore,
|
||||
out long totalAfter
|
||||
)
|
||||
{
|
||||
Attempt<int> targetIdAttempt = _idKeyMap.GetIdForKey(targetKey, umbracoObjectType);
|
||||
if (targetIdAttempt.Success is false)
|
||||
{
|
||||
totalBefore = 0;
|
||||
totalAfter = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -154,6 +172,8 @@ public class UserStartNodeEntitiesService : IUserStartNodeEntitiesService
|
||||
IEntitySlim? target = _entityService.Get(targetId);
|
||||
if (target is null)
|
||||
{
|
||||
totalBefore = 0;
|
||||
totalAfter = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -162,13 +182,15 @@ public class UserStartNodeEntitiesService : IUserStartNodeEntitiesService
|
||||
IEntitySlim? targetParent = _entityService.Get(target.ParentId);
|
||||
if (targetParent is null) // Even if the parent is the root, we still expect to get a value here.
|
||||
{
|
||||
totalBefore = 0;
|
||||
totalAfter = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
if (userStartNodePaths.Any(path => $"{targetParent?.Path},".StartsWith($"{path},")))
|
||||
{
|
||||
// The requested parent of the target is one of the user start nodes (or a descendant of one), all siblings are by definition allowed.
|
||||
siblings = _entityService.GetSiblings(targetKey, umbracoObjectType, before, after, ordering: ordering).ToArray();
|
||||
siblings = _entityService.GetSiblings(targetKey, umbracoObjectType, before, after, out totalBefore, out totalAfter, ordering: ordering).ToArray();
|
||||
return ChildUserAccessEntities(siblings, userStartNodePaths);
|
||||
}
|
||||
|
||||
@@ -177,12 +199,14 @@ public class UserStartNodeEntitiesService : IUserStartNodeEntitiesService
|
||||
if (allowedSiblingIds.Length == 0)
|
||||
{
|
||||
// The requested target is outside the scope of any user start nodes.
|
||||
totalBefore = 0;
|
||||
totalAfter = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
// Even though we know the IDs of the allowed sibling entities to fetch, we still use a Query to yield correctly sorted children.
|
||||
IQuery<IUmbracoEntity> query = _scopeProvider.CreateQuery<IUmbracoEntity>().Where(x => allowedSiblingIds.Contains(x.Id));
|
||||
siblings = _entityService.GetSiblings(targetKey, umbracoObjectType, before, after, query, ordering).ToArray();
|
||||
siblings = _entityService.GetSiblings(targetKey, umbracoObjectType, before, after, out totalBefore, out totalAfter, query, ordering).ToArray();
|
||||
return ChildUserAccessEntities(siblings, userStartNodePaths);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,23 @@ public interface IEntityRepository : IRepository
|
||||
/// <param name="after">The number of siblings to retrieve after the target entity.</param>
|
||||
/// <param name="filter">An optional filter to apply to the result set.</param>
|
||||
/// <param name="ordering">The ordering to apply to the siblings.</param>
|
||||
/// <param name="totalBefore">Outputs the total number of siblings before the target entity.</param>
|
||||
/// <param name="totalAfter">Outputs the total number of siblings after the target entity.</param>
|
||||
/// <returns>Enumerable of sibling entities.</returns>
|
||||
IEnumerable<IEntitySlim> GetSiblings(Guid objectType, Guid targetKey, int before, int after, IQuery<IUmbracoEntity>? filter, Ordering ordering) => [];
|
||||
IEnumerable<IEntitySlim> GetSiblings(
|
||||
Guid objectType,
|
||||
Guid targetKey,
|
||||
int before,
|
||||
int after,
|
||||
IQuery<IUmbracoEntity>? filter,
|
||||
Ordering ordering,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
{
|
||||
totalBefore = 0;
|
||||
totalAfter = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets entities for a query
|
||||
|
||||
@@ -324,6 +324,8 @@ public class EntityService : RepositoryService, IEntityService
|
||||
UmbracoObjectTypes objectType,
|
||||
int before,
|
||||
int after,
|
||||
out long totalBefore,
|
||||
out long totalAfter,
|
||||
IQuery<IUmbracoEntity>? filter = null,
|
||||
Ordering? ordering = null)
|
||||
{
|
||||
@@ -347,7 +349,9 @@ public class EntityService : RepositoryService, IEntityService
|
||||
before,
|
||||
after,
|
||||
filter,
|
||||
ordering);
|
||||
ordering,
|
||||
out totalBefore,
|
||||
out totalAfter);
|
||||
|
||||
scope.Complete();
|
||||
return siblings;
|
||||
|
||||
@@ -179,14 +179,23 @@ public interface IEntityService
|
||||
/// <param name="after">The number of siblings to retrieve after the target entity. Needs to be greater or equal to 0.</param>
|
||||
/// <param name="filter">An optional filter to apply to the result set.</param>
|
||||
/// <param name="ordering">The ordering to apply to the siblings.</param>
|
||||
/// <param name="totalBefore">Outputs the total number of siblings before the target entity.</param>
|
||||
/// <param name="totalAfter">Outputs the total number of siblings after the target entity.</param>
|
||||
/// <returns>Enumerable of sibling entities.</returns>
|
||||
IEnumerable<IEntitySlim> GetSiblings(
|
||||
Guid key,
|
||||
UmbracoObjectTypes objectType,
|
||||
int before,
|
||||
int after,
|
||||
out long totalBefore,
|
||||
out long totalAfter,
|
||||
IQuery<IUmbracoEntity>? filter = null,
|
||||
Ordering? ordering = null) => [];
|
||||
Ordering? ordering = null)
|
||||
{
|
||||
totalBefore = 0;
|
||||
totalAfter = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children of an entity.
|
||||
|
||||
@@ -152,7 +152,9 @@ internal sealed class EntityRepository : RepositoryBase, IEntityRepositoryExtend
|
||||
int before,
|
||||
int after,
|
||||
IQuery<IUmbracoEntity>? filter,
|
||||
Ordering ordering)
|
||||
Ordering ordering,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
{
|
||||
// Ideally we don't want to have to do a second query for the parent ID, but the siblings query is already messy enough
|
||||
// without us also having to do a nested query for the parent ID too.
|
||||
@@ -204,15 +206,21 @@ internal sealed class EntityRepository : RepositoryBase, IEntityRepositoryExtend
|
||||
|
||||
// Select the UniqueId of nodes which row number is within the specified range of the target node's row number.
|
||||
const int BeforeAfterParameterIndex = 3;
|
||||
var beforeAfterParameterIndex = BeforeAfterParameterIndex + beforeAfterParameterIndexOffset;
|
||||
var beforeArgumentsArray = beforeArguments.ToArray();
|
||||
var afterArgumentsArray = afterArguments.ToArray();
|
||||
Sql<ISqlContext>? mainSql = Sql()
|
||||
.Select("UniqueId")
|
||||
.From().AppendSubQuery(rowNumberSql, "NumberedNodes")
|
||||
.Where($"rn >= ({targetRowSql.SQL}) - @{BeforeAfterParameterIndex + beforeAfterParameterIndexOffset}", beforeArguments.ToArray())
|
||||
.Where($"rn <= ({targetRowSql.SQL}) + @{BeforeAfterParameterIndex + beforeAfterParameterIndexOffset}", afterArguments.ToArray())
|
||||
.Where($"rn >= ({targetRowSql.SQL}) - @{beforeAfterParameterIndex}", beforeArgumentsArray)
|
||||
.Where($"rn <= ({targetRowSql.SQL}) + @{beforeAfterParameterIndex}", afterArgumentsArray)
|
||||
.OrderBy("rn");
|
||||
|
||||
List<Guid>? keys = Database.Fetch<Guid>(mainSql);
|
||||
|
||||
totalBefore = GetNumberOfSiblingsOutsideSiblingRange(rowNumberSql, targetRowSql, beforeAfterParameterIndex, beforeArgumentsArray, true);
|
||||
totalAfter = GetNumberOfSiblingsOutsideSiblingRange(rowNumberSql, targetRowSql, beforeAfterParameterIndex, afterArgumentsArray, false);
|
||||
|
||||
if (keys is null || keys.Count == 0)
|
||||
{
|
||||
return [];
|
||||
@@ -221,6 +229,20 @@ internal sealed class EntityRepository : RepositoryBase, IEntityRepositoryExtend
|
||||
return PerformGetAll(objectType, ordering, sql => sql.WhereIn<NodeDto>(x => x.UniqueId, keys));
|
||||
}
|
||||
|
||||
private long GetNumberOfSiblingsOutsideSiblingRange(
|
||||
Sql<ISqlContext> rowNumberSql,
|
||||
Sql<ISqlContext> targetRowSql,
|
||||
int parameterIndex,
|
||||
object[] arguments,
|
||||
bool getBefore)
|
||||
{
|
||||
Sql<ISqlContext>? sql = Sql()
|
||||
.SelectCount()
|
||||
.From().AppendSubQuery(rowNumberSql, "NumberedNodes")
|
||||
.Where($"rn {(getBefore ? "<" : ">")} ({targetRowSql.SQL}) {(getBefore ? "-" : "+")} @{parameterIndex}", arguments);
|
||||
return Database.ExecuteScalar<long>(sql);
|
||||
}
|
||||
|
||||
|
||||
public IEntitySlim? Get(Guid key, Guid objectTypeId)
|
||||
{
|
||||
|
||||
@@ -17,9 +17,13 @@ public partial class UserStartNodeEntitiesServiceMediaTests
|
||||
_mediaByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalBefore);
|
||||
Assert.AreEqual(3, totalAfter);
|
||||
Assert.AreEqual(5, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -45,9 +49,13 @@ public partial class UserStartNodeEntitiesServiceMediaTests
|
||||
_mediaByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(0, totalAfter);
|
||||
Assert.AreEqual(1, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -68,9 +76,13 @@ public partial class UserStartNodeEntitiesServiceMediaTests
|
||||
_mediaByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(0, totalAfter);
|
||||
Assert.AreEqual(1, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -82,18 +94,22 @@ public partial class UserStartNodeEntitiesServiceMediaTests
|
||||
[Test]
|
||||
public async Task SiblingUserAccessEntities_WithStartsNodesOfTargetAndSiblings_YieldsOnlyPermitted_AsAllowed()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["1-3"].Id, _mediaByName["1-5"].Id, _mediaByName["1-7"].Id);
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["1-3"].Id, _mediaByName["1-5"].Id, _mediaByName["1-7"].Id, _mediaByName["1-10"].Id);
|
||||
|
||||
var siblings = UserStartNodeEntitiesService
|
||||
.SiblingUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
1,
|
||||
1,
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(1, totalAfter);
|
||||
Assert.AreEqual(3, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -118,9 +134,13 @@ public partial class UserStartNodeEntitiesServiceMediaTests
|
||||
_mediaByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(0, totalAfter);
|
||||
Assert.AreEqual(1, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
|
||||
@@ -17,9 +17,13 @@ public partial class UserStartNodeEntitiesServiceTests
|
||||
_contentByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalBefore);
|
||||
Assert.AreEqual(3, totalAfter);
|
||||
Assert.AreEqual(5, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -45,9 +49,13 @@ public partial class UserStartNodeEntitiesServiceTests
|
||||
_contentByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(0, totalAfter);
|
||||
Assert.AreEqual(1, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -68,9 +76,13 @@ public partial class UserStartNodeEntitiesServiceTests
|
||||
_contentByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(0, totalAfter);
|
||||
Assert.AreEqual(1, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
@@ -82,19 +94,24 @@ public partial class UserStartNodeEntitiesServiceTests
|
||||
[Test]
|
||||
public async Task SiblingUserAccessEntities_WithStartsNodesOfTargetAndSiblings_YieldsOnlyPermitted_AsAllowed()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["1-3"].Id, _contentByName["1-5"].Id, _contentByName["1-7"].Id);
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["1-3"].Id, _contentByName["1-5"].Id, _contentByName["1-7"].Id, _contentByName["1-10"].Id);
|
||||
|
||||
var siblings = UserStartNodeEntitiesService
|
||||
.SiblingUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
1,
|
||||
1,
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(1, totalAfter);
|
||||
Assert.AreEqual(3, siblings.Length);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_contentByName[$"1-3"].Key, siblings[0].Entity.Key);
|
||||
@@ -118,9 +135,13 @@ public partial class UserStartNodeEntitiesServiceTests
|
||||
_contentByName["1-5"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder)
|
||||
BySortOrder,
|
||||
out long totalBefore,
|
||||
out long totalAfter)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(0, totalAfter);
|
||||
Assert.AreEqual(1, siblings.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
|
||||
@@ -929,7 +929,6 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
|
||||
var result2 = EntityService.GetPathKeys(grandChild, omitSelf: true);
|
||||
Assert.AreEqual($"{root.Key},{child.Key}", string.Join(",", result2));
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -939,7 +938,9 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
|
||||
var target = children[1];
|
||||
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1).ToArray();
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, out long totalBefore, out long totalAfter).ToArray();
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(7, totalAfter);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
Assert.IsTrue(result[0].Key == children[0].Key);
|
||||
Assert.IsTrue(result[1].Key == children[1].Key);
|
||||
@@ -955,7 +956,9 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
ContentService.MoveToRecycleBin(trash);
|
||||
|
||||
var target = children[2];
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1).ToArray();
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, out long totalBefore, out long totalAfter).ToArray();
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(6, totalAfter);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
Assert.IsFalse(result.Any(x => x.Key == trash.Key));
|
||||
Assert.IsTrue(result[0].Key == children[0].Key);
|
||||
@@ -974,7 +977,9 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
IQuery<IUmbracoEntity> filter = ScopeProvider.CreateQuery<IUmbracoEntity>().Where(x => !keysToExclude.Contains(x.Key));
|
||||
|
||||
var target = children[2];
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, filter).ToArray();
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, out long totalBefore, out long totalAfter, filter).ToArray();
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(6, totalAfter);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
Assert.IsFalse(result.Any(x => x.Key == keysToExclude[0]));
|
||||
Assert.IsTrue(result[0].Key == children[0].Key);
|
||||
@@ -993,7 +998,9 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
IQuery<IUmbracoEntity> filter = ScopeProvider.CreateQuery<IUmbracoEntity>().Where(x => x.Key != keyToExclude);
|
||||
|
||||
var target = children[2];
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, filter).ToArray();
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, out long totalBefore, out long totalAfter, filter).ToArray();
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(6, totalAfter);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
Assert.IsFalse(result.Any(x => x.Key == keyToExclude));
|
||||
Assert.IsTrue(result[0].Key == children[0].Key);
|
||||
@@ -1010,7 +1017,9 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
children = children.OrderBy(x => x.Name).ToList();
|
||||
|
||||
var target = children[1];
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, ordering: Ordering.By(nameof(NodeDto.Text))).ToArray();
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 1, out long totalBefore, out long totalAfter, ordering: Ordering.By(nameof(NodeDto.Text))).ToArray();
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(7, totalAfter);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
Assert.IsTrue(result[0].Key == children[0].Key);
|
||||
Assert.IsTrue(result[1].Key == children[1].Key);
|
||||
@@ -1023,7 +1032,9 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
var children = CreateSiblingsTestData();
|
||||
|
||||
var target = children[1];
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 100, 1).ToArray();
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 100, 1, out long totalBefore, out long totalAfter).ToArray();
|
||||
Assert.AreEqual(0, totalBefore);
|
||||
Assert.AreEqual(7, totalAfter);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
Assert.IsTrue(result[0].Key == children[0].Key);
|
||||
Assert.IsTrue(result[1].Key == children[1].Key);
|
||||
@@ -1036,7 +1047,9 @@ internal sealed class EntityServiceTests : UmbracoIntegrationTest
|
||||
var children = CreateSiblingsTestData();
|
||||
|
||||
var target = children[^2];
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 100).ToArray();
|
||||
var result = EntityService.GetSiblings(target.Key, UmbracoObjectTypes.Document, 1, 100, out long totalBefore, out long totalAfter).ToArray();
|
||||
Assert.AreEqual(7, totalBefore);
|
||||
Assert.AreEqual(0, totalAfter);
|
||||
Assert.AreEqual(3, result.Length);
|
||||
Assert.IsTrue(result[^1].Key == children[^1].Key);
|
||||
Assert.IsTrue(result[^2].Key == children[^2].Key);
|
||||
|
||||
@@ -23,7 +23,7 @@ public class EntityServiceTests
|
||||
|
||||
if (shouldThrow)
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => sut.GetSiblings(Guid.NewGuid(), UmbracoObjectTypes.Document, before, after));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => sut.GetSiblings(Guid.NewGuid(), UmbracoObjectTypes.Document, before, after, out _, out _));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user