Skip to content

Commit fcba10a

Browse files
AndyButlandCopilotnikolajlauridsen
authored
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 <[email protected]> * 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 <[email protected]> Co-authored-by: mole <[email protected]>
1 parent 20254f0 commit fcba10a

File tree

21 files changed

+526
-115
lines changed

21 files changed

+526
-115
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace Umbraco.Cms.Api.Common.ViewModels.Pagination;
4+
5+
public class SubsetViewModel<T>
6+
{
7+
[Required]
8+
public long TotalBefore { get; set; }
9+
10+
[Required]
11+
public long TotalAfter { get; set; }
12+
13+
[Required]
14+
public IEnumerable<T> Items { get; set; } = Enumerable.Empty<T>();
15+
16+
public static SubsetViewModel<T> Empty() => new();
17+
}

src/Umbraco.Cms.Api.Management/Controllers/DataType/Tree/SiblingsDataTypeTreeController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Http;
22
using Microsoft.AspNetCore.Mvc;
3+
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
34
using Umbraco.Cms.Api.Management.ViewModels.Tree;
45
using Umbraco.Cms.Core.Services;
56

@@ -13,7 +14,7 @@ public SiblingsDataTypeTreeController(IEntityService entityService, IDataTypeSer
1314
}
1415

1516
[HttpGet("siblings")]
16-
[ProducesResponseType(typeof(IEnumerable<DataTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
17-
public Task<ActionResult<IEnumerable<DataTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
17+
[ProducesResponseType(typeof(SubsetViewModel<DataTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
18+
public Task<ActionResult<SubsetViewModel<DataTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
1819
=> GetSiblings(target, before, after);
1920
}

src/Umbraco.Cms.Api.Management/Controllers/Document/Tree/SiblingsDocumentTreeController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using Asp.Versioning;
22
using Microsoft.AspNetCore.Http;
33
using Microsoft.AspNetCore.Mvc;
4+
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
45
using Umbraco.Cms.Api.Management.Factories;
56
using Umbraco.Cms.Api.Management.Services.Entities;
67
using Umbraco.Cms.Api.Management.ViewModels.Tree;
@@ -34,8 +35,8 @@ public SiblingsDocumentTreeController(
3435

3536
[HttpGet("siblings")]
3637
[MapToApiVersion("1.0")]
37-
[ProducesResponseType(typeof(IEnumerable<DocumentTreeItemResponseModel>), StatusCodes.Status200OK)]
38-
public Task<ActionResult<IEnumerable<DocumentTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
38+
[ProducesResponseType(typeof(SubsetViewModel<DocumentTreeItemResponseModel>), StatusCodes.Status200OK)]
39+
public Task<ActionResult<SubsetViewModel<DocumentTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
3940
{
4041
IgnoreUserStartNodesForDataType(dataTypeId);
4142
return GetSiblings(target, before, after);

src/Umbraco.Cms.Api.Management/Controllers/DocumentBlueprint/Tree/SiblingsDocumentBlueprintTreeController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Http;
22
using Microsoft.AspNetCore.Mvc;
3+
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
34
using Umbraco.Cms.Api.Management.Factories;
45
using Umbraco.Cms.Api.Management.ViewModels.Tree;
56
using Umbraco.Cms.Core.Services;
@@ -14,8 +15,8 @@ public SiblingsDocumentBlueprintTreeController(IEntityService entityService, IDo
1415
}
1516

1617
[HttpGet("siblings")]
17-
[ProducesResponseType(typeof(IEnumerable<DocumentBlueprintTreeItemResponseModel>), StatusCodes.Status200OK)]
18-
public Task<ActionResult<IEnumerable<DocumentBlueprintTreeItemResponseModel>>> Siblings(
18+
[ProducesResponseType(typeof(SubsetViewModel<DocumentBlueprintTreeItemResponseModel>), StatusCodes.Status200OK)]
19+
public Task<ActionResult<SubsetViewModel<DocumentBlueprintTreeItemResponseModel>>> Siblings(
1920
CancellationToken cancellationToken,
2021
Guid target,
2122
int before,

src/Umbraco.Cms.Api.Management/Controllers/DocumentType/Tree/SiblingsDocumentTypeTreeController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Http;
22
using Microsoft.AspNetCore.Mvc;
3+
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
34
using Umbraco.Cms.Api.Management.ViewModels.Tree;
45
using Umbraco.Cms.Core.Services;
56

@@ -13,8 +14,8 @@ public SiblingsDocumentTypeTreeController(IEntityService entityService, IContent
1314
}
1415

1516
[HttpGet("siblings")]
16-
[ProducesResponseType(typeof(IEnumerable<DocumentTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
17-
public Task<ActionResult<IEnumerable<DocumentTypeTreeItemResponseModel>>> Siblings(
17+
[ProducesResponseType(typeof(SubsetViewModel<DocumentTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
18+
public Task<ActionResult<SubsetViewModel<DocumentTypeTreeItemResponseModel>>> Siblings(
1819
CancellationToken cancellationToken,
1920
Guid target,
2021
int before,

src/Umbraco.Cms.Api.Management/Controllers/Media/Tree/SiblingsMediaTreeController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Http;
22
using Microsoft.AspNetCore.Mvc;
3+
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
34
using Umbraco.Cms.Api.Management.Factories;
45
using Umbraco.Cms.Api.Management.Services.Entities;
56
using Umbraco.Cms.Api.Management.ViewModels.Tree;
@@ -23,8 +24,8 @@ public SiblingsMediaTreeController(
2324
}
2425

2526
[HttpGet("siblings")]
26-
[ProducesResponseType(typeof(IEnumerable<MediaTreeItemResponseModel>), StatusCodes.Status200OK)]
27-
public Task<ActionResult<IEnumerable<MediaTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
27+
[ProducesResponseType(typeof(SubsetViewModel<MediaTreeItemResponseModel>), StatusCodes.Status200OK)]
28+
public Task<ActionResult<SubsetViewModel<MediaTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after, Guid? dataTypeId = null)
2829
{
2930
IgnoreUserStartNodesForDataType(dataTypeId);
3031
return GetSiblings(target, before, after);

src/Umbraco.Cms.Api.Management/Controllers/MediaType/Tree/SiblingsMediaTypeTreeController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Http;
22
using Microsoft.AspNetCore.Mvc;
3+
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
34
using Umbraco.Cms.Api.Management.ViewModels.Tree;
45
using Umbraco.Cms.Core.Services;
56

@@ -13,7 +14,7 @@ public SiblingsMediaTypeTreeController(IEntityService entityService, IMediaTypeS
1314
}
1415

1516
[HttpGet("siblings")]
16-
[ProducesResponseType(typeof(IEnumerable<MediaTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
17-
public Task<ActionResult<IEnumerable<MediaTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
17+
[ProducesResponseType(typeof(SubsetViewModel<MediaTypeTreeItemResponseModel>), StatusCodes.Status200OK)]
18+
public Task<ActionResult<SubsetViewModel<MediaTypeTreeItemResponseModel>>> Siblings(CancellationToken cancellationToken, Guid target, int before, int after)
1819
=> GetSiblings(target, before, after);
1920
}

src/Umbraco.Cms.Api.Management/Controllers/Template/Tree/SiblingsTemplateTreeController.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Http;
22
using Microsoft.AspNetCore.Mvc;
3+
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
34
using Umbraco.Cms.Api.Management.ViewModels.Tree;
45
using Umbraco.Cms.Core.Services;
56

@@ -13,8 +14,8 @@ public SiblingsTemplateTreeController(IEntityService entityService)
1314
}
1415

1516
[HttpGet("siblings")]
16-
[ProducesResponseType(typeof(IEnumerable<NamedEntityTreeItemResponseModel>), StatusCodes.Status200OK)]
17-
public Task<ActionResult<IEnumerable<NamedEntityTreeItemResponseModel>>> Siblings(
17+
[ProducesResponseType(typeof(SubsetViewModel<NamedEntityTreeItemResponseModel>), StatusCodes.Status200OK)]
18+
public Task<ActionResult<SubsetViewModel<NamedEntityTreeItemResponseModel>>> Siblings(
1819
CancellationToken cancellationToken,
1920
Guid target,
2021
int before,

src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,24 @@ protected Task<ActionResult<PagedViewModel<TItem>>> GetChildren(Guid parentId, i
4444
return Task.FromResult<ActionResult<PagedViewModel<TItem>>>(Ok(result));
4545
}
4646

47-
protected Task<ActionResult<IEnumerable<TItem>>> GetSiblings(Guid target, int before, int after)
47+
protected Task<ActionResult<SubsetViewModel<TItem>>> GetSiblings(Guid target, int before, int after)
4848
{
49-
IEntitySlim[] siblings = GetSiblingEntities(target, before, after);
49+
IEntitySlim[] siblings = GetSiblingEntities(target, before, after, out var totalBefore, out var totalAfter);
5050
if (siblings.Length == 0)
5151
{
52-
return Task.FromResult<ActionResult<IEnumerable<TItem>>>(NotFound());
52+
return Task.FromResult<ActionResult<SubsetViewModel<TItem>>>(NotFound());
5353
}
5454

5555
IEntitySlim? entity = siblings.FirstOrDefault();
5656
Guid? parentKey = entity?.ParentId > 0
5757
? EntityService.GetKey(entity.ParentId, ItemObjectType).Result
5858
: Constants.System.RootKey;
5959

60-
TItem[] treeItemsViewModels = MapTreeItemViewModels(parentKey, siblings);
61-
return Task.FromResult<ActionResult<IEnumerable<TItem>>>(Ok(treeItemsViewModels));
60+
TItem[] treeItemViewModels = MapTreeItemViewModels(parentKey, siblings);
61+
62+
SubsetViewModel<TItem> result = SubsetViewModel(treeItemViewModels, totalBefore, totalAfter);
63+
64+
return Task.FromResult<ActionResult<SubsetViewModel<TItem>>>(Ok(result));
6265
}
6366

6467
protected virtual async Task<ActionResult<IEnumerable<TItem>>> GetAncestors(Guid descendantKey, bool includeSelf = true)
@@ -120,13 +123,15 @@ protected virtual IEntitySlim[] GetPagedChildEntities(Guid parentKey, int skip,
120123
ordering: ItemOrdering)
121124
.ToArray();
122125

123-
protected virtual IEntitySlim[] GetSiblingEntities(Guid target, int before, int after) =>
126+
protected virtual IEntitySlim[] GetSiblingEntities(Guid target, int before, int after, out long totalBefore, out long totalAfter) =>
124127
EntityService
125128
.GetSiblings(
126129
target,
127130
ItemObjectType,
128131
before,
129132
after,
133+
out totalBefore,
134+
out totalAfter,
130135
ordering: ItemOrdering)
131136
.ToArray();
132137

@@ -152,4 +157,7 @@ protected virtual TItem MapTreeItemViewModel(Guid? parentKey, IEntitySlim entity
152157

153158
protected PagedViewModel<TItem> PagedViewModel(IEnumerable<TItem> treeItemViewModels, long totalItems)
154159
=> new() { Total = totalItems, Items = treeItemViewModels };
160+
161+
protected SubsetViewModel<TItem> SubsetViewModel(IEnumerable<TItem> treeItemViewModels, long totalBefore, long totalAfter)
162+
=> new() { TotalBefore = totalBefore, TotalAfter = totalAfter, Items = treeItemViewModels };
155163
}

src/Umbraco.Cms.Api.Management/Controllers/Tree/UserStartNodeTreeControllerBase.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,11 @@ protected override IEntitySlim[] GetPagedChildEntities(Guid parentKey, int skip,
5959
return CalculateAccessMap(() => userAccessEntities, out _);
6060
}
6161

62-
protected override IEntitySlim[] GetSiblingEntities(Guid target, int before, int after)
62+
protected override IEntitySlim[] GetSiblingEntities(Guid target, int before, int after, out long totalBefore, out long totalAfter)
6363
{
6464
if (UserHasRootAccess() || IgnoreUserStartNodes())
6565
{
66-
return base.GetSiblingEntities(target, before, after);
66+
return base.GetSiblingEntities(target, before, after, out totalBefore, out totalAfter);
6767
}
6868

6969
IEnumerable<UserAccessEntity> userAccessEntities = _userStartNodeEntitiesService.SiblingUserAccessEntities(
@@ -72,7 +72,9 @@ protected override IEntitySlim[] GetSiblingEntities(Guid target, int before, int
7272
target,
7373
before,
7474
after,
75-
ItemOrdering);
75+
ItemOrdering,
76+
out totalBefore,
77+
out totalAfter);
7678

7779
return CalculateAccessMap(() => userAccessEntities, out _);
7880
}

0 commit comments

Comments
 (0)