From ae675b28f76573b402c8a1eae8383d127cb489a6 Mon Sep 17 00:00:00 2001 From: Mole Date: Tue, 12 Mar 2024 12:57:29 +0100 Subject: [PATCH] V14: Remove duplicate pagination helper (#15856) * Remove management PaginationService * Remove usage of PaginationHelper in FilterMemberFilterController --- .../DocumentRecycleBinControllerBase.cs | 2 +- .../MediaRecycleBinControllerBase.cs | 2 +- .../Filter/FilterMemberFilterController.cs | 6 +- .../RecycleBin/RecycleBinControllerBase.cs | 25 ++-- .../GetAllRedirectUrlManagementController.cs | 12 +- .../Tree/EntityTreeControllerBase.cs | 45 ++------ .../Tree/FileSystemTreeControllerBase.cs | 21 +--- .../Tree/FolderTreeControllerBase.cs | 59 ++++------ .../Tree/UserStartNodeTreeControllerBase.cs | 8 +- .../Services/Paging/PaginationService.cs | 39 ------- src/Umbraco.Core/Constants-System.cs | 10 ++ src/Umbraco.Core/Services/EntityService.cs | 108 ++++++++++++++++++ src/Umbraco.Core/Services/IEntityService.cs | 36 ++++++ src/Umbraco.Core/Services/IMemberService.cs | 35 ++++++ .../Services/IRedirectUrlService.cs | 29 +++++ .../Migrations/Install/DatabaseDataCreator.cs | 8 +- 16 files changed, 278 insertions(+), 167 deletions(-) delete mode 100644 src/Umbraco.Cms.Api.Management/Services/Paging/PaginationService.cs diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs index ce2340cca6..42944736f6 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs @@ -27,7 +27,7 @@ public class DocumentRecycleBinControllerBase : RecycleBinControllerBase UmbracoObjectTypes.Document; - protected override int RecycleBinRootId => Constants.System.RecycleBinContent; + protected override Guid RecycleBindRootKey => Constants.System.RecycleBinContentKey; protected override DocumentRecycleBinItemResponseModel MapRecycleBinViewModel(Guid? parentId, IEntitySlim entity) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs index e4a80ad624..60e913850c 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs @@ -27,7 +27,7 @@ public class MediaRecycleBinControllerBase : RecycleBinControllerBase UmbracoObjectTypes.Media; - protected override int RecycleBinRootId => Constants.System.RecycleBinMedia; + protected override Guid RecycleBindRootKey => Constants.System.RecycleBinMediaKey; protected override MediaRecycleBinItemResponseModel MapRecycleBinViewModel(Guid? parentKey, IEntitySlim entity) { diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Member/Filter/FilterMemberFilterController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Member/Filter/FilterMemberFilterController.cs index bba4750061..3814dc5fc5 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Member/Filter/FilterMemberFilterController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Member/Filter/FilterMemberFilterController.cs @@ -52,11 +52,9 @@ public class FilterMemberFilterController : MemberFilterControllerBase memberTypeAlias = memberType.Alias; } - PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize); - IEnumerable members = await Task.FromResult(_memberService.GetAll( - pageNumber, - pageSize, + skip, + take, out var totalRecords, orderBy, orderDirection, diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs index 19013df03a..978eafc39c 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/RecycleBin/RecycleBinControllerBase.cs @@ -2,7 +2,6 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; using Umbraco.Cms.Api.Management.Controllers.Content; -using Umbraco.Cms.Api.Management.Services.Paging; using Umbraco.Cms.Api.Management.ViewModels.Item; using Umbraco.Cms.Api.Management.ViewModels.RecycleBin; using Umbraco.Cms.Core.Models; @@ -27,16 +26,11 @@ public abstract class RecycleBinControllerBase : ContentControllerBase protected abstract UmbracoObjectTypes ItemObjectType { get; } - protected abstract int RecycleBinRootId { get; } + protected abstract Guid RecycleBindRootKey { get; } protected async Task>> GetRoot(int skip, int take) { - if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) - { - return BadRequest(error); - } - - IEntitySlim[] rootEntities = GetPagedRootEntities(pageNumber, pageSize, out var totalItems); + IEntitySlim[] rootEntities = GetPagedRootEntities(skip, take, out var totalItems); TItem[] treeItemViewModels = MapRecycleBinViewModels(null, rootEntities); @@ -46,12 +40,7 @@ public abstract class RecycleBinControllerBase : ContentControllerBase protected async Task>> GetChildren(Guid parentKey, int skip, int take) { - if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) - { - return BadRequest(error); - } - - IEntitySlim[] children = GetPagedChildEntities(parentKey, pageNumber, pageSize, out var totalItems); + IEntitySlim[] children = GetPagedChildEntities(parentKey, skip, take, out var totalItems); TItem[] treeItemViewModels = MapRecycleBinViewModels(parentKey, children); @@ -120,16 +109,16 @@ public abstract class RecycleBinControllerBase : ContentControllerBase .Build()), }); - private IEntitySlim[] GetPagedRootEntities(long pageNumber, int pageSize, out long totalItems) + private IEntitySlim[] GetPagedRootEntities(int skip, int take, out long totalItems) { IEntitySlim[] rootEntities = _entityService - .GetPagedTrashedChildren(RecycleBinRootId, ItemObjectType, pageNumber, pageSize, out totalItems) + .GetPagedTrashedChildren(RecycleBindRootKey, ItemObjectType, skip, take, out totalItems) .ToArray(); return rootEntities; } - private IEntitySlim[] GetPagedChildEntities(Guid parentKey, long pageNumber, int pageSize, out long totalItems) + private IEntitySlim[] GetPagedChildEntities(Guid parentKey, int skip, int take, out long totalItems) { IEntitySlim? parent = _entityService.Get(parentKey, ItemObjectType); if (parent == null || parent.Trashed == false) @@ -140,7 +129,7 @@ public abstract class RecycleBinControllerBase : ContentControllerBase } IEntitySlim[] children = _entityService - .GetPagedTrashedChildren(parent.Id, ItemObjectType, pageNumber, pageSize, out totalItems) + .GetPagedTrashedChildren(parentKey, ItemObjectType, skip, take, out totalItems) .ToArray(); return children; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs index edda41c3b4..07238f62f9 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/RedirectUrlManagement/GetAllRedirectUrlManagementController.cs @@ -3,7 +3,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.Paging; using Umbraco.Cms.Api.Management.ViewModels.RedirectUrlManagement; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; @@ -28,17 +27,12 @@ public class GetAllRedirectUrlManagementController : RedirectUrlManagementContro [HttpGet] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task>> GetAll(string? filter, int skip = 0, int take = 100) + public async Task>> GetAll(string? filter, int skip = 0, int take = 100) { - if (PaginationService.ConvertSkipTakeToPaging(skip, take, out long pageNumber, out int pageSize, out ProblemDetails? error) is false) - { - return BadRequest(error); - } - long total; IEnumerable redirects = filter is null - ? _redirectUrlService.GetAllRedirectUrls(pageNumber, pageSize, out total) - : _redirectUrlService.SearchRedirectUrls(filter, pageNumber, pageSize, out total); + ? _redirectUrlService.GetAllRedirectUrls(skip, take, out total) + : _redirectUrlService.SearchRedirectUrls(filter, skip, take, out total); IEnumerable redirectViewModels = _redirectUrlPresentationFactory.CreateMany(redirects); return new PagedViewModel { Items = redirectViewModels, Total = total }; diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs index d8d3d3ffdd..e8c11651cf 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Tree/EntityTreeControllerBase.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; -using Umbraco.Cms.Api.Management.Services.Paging; using Umbraco.Cms.Api.Management.ViewModels; using Umbraco.Cms.Api.Management.ViewModels.Tree; using Umbraco.Cms.Core; @@ -32,12 +31,7 @@ public abstract class EntityTreeControllerBase : ManagementApiControllerB protected async Task>> GetRoot(int skip, int take) { - if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) - { - return BadRequest(error); - } - - IEntitySlim[] rootEntities = GetPagedRootEntities(pageNumber, pageSize, out var totalItems); + IEntitySlim[] rootEntities = GetPagedRootEntities(skip, take, out var totalItems); TItem[] treeItemViewModels = MapTreeItemViewModels(null, rootEntities); @@ -47,12 +41,7 @@ public abstract class EntityTreeControllerBase : ManagementApiControllerB protected async Task>> GetChildren(Guid parentId, int skip, int take) { - if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) - { - return BadRequest(error); - } - - IEntitySlim[] children = GetPagedChildEntities(parentId, pageNumber, pageSize, out var totalItems); + IEntitySlim[] children = GetPagedChildEntities(parentId, skip, take, out var totalItems); TItem[] treeItemViewModels = MapTreeItemViewModels(parentId, children); @@ -74,38 +63,26 @@ public abstract class EntityTreeControllerBase : ManagementApiControllerB return await Task.FromResult(Ok(treeItemViewModels)); } - protected virtual IEntitySlim[] GetPagedRootEntities(long pageNumber, int pageSize, out long totalItems) + protected virtual IEntitySlim[] GetPagedRootEntities(int skip, int take, out long totalItems) => EntityService .GetPagedChildren( - Constants.System.Root, + Constants.System.RootKey, ItemObjectType, - pageNumber, - pageSize, + skip, + take, out totalItems, ordering: ItemOrdering) .ToArray(); - protected virtual IEntitySlim[] GetPagedChildEntities(Guid parentKey, long pageNumber, int pageSize, out long totalItems) - { - // EntityService is only able to get paged children by parent ID, so we must first map parent id to parent ID - Attempt parentId = EntityService.GetId(parentKey, ItemObjectType); - if (parentId.Success == false) - { - // not much else we can do here but return nothing - totalItems = 0; - return Array.Empty(); - } - - IEntitySlim[] children = EntityService.GetPagedChildren( - parentId.Result, + protected virtual IEntitySlim[] GetPagedChildEntities(Guid parentKey, int skip, int take, out long totalItems) => + EntityService.GetPagedChildren( + parentKey, ItemObjectType, - pageNumber, - pageSize, + skip, + take, out totalItems, ordering: ItemOrdering) .ToArray(); - return children; - } protected virtual IEntitySlim[] GetEntities(Guid[] ids) => EntityService.GetAll(ItemObjectType, ids).ToArray(); diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Tree/FileSystemTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Tree/FileSystemTreeControllerBase.cs index fecad5b85b..9964a287a6 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Tree/FileSystemTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Tree/FileSystemTreeControllerBase.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Api.Common.ViewModels.Pagination; using Umbraco.Cms.Api.Management.Extensions; -using Umbraco.Cms.Api.Management.Services.Paging; using Umbraco.Cms.Api.Management.ViewModels.FileSystem; using Umbraco.Cms.Api.Management.ViewModels.Tree; using Umbraco.Cms.Core.IO; @@ -17,12 +16,7 @@ public abstract class FileSystemTreeControllerBase : ManagementApiControllerBase protected async Task>> GetRoot(int skip, int take) { - if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) - { - return BadRequest(error); - } - - FileSystemTreeItemPresentationModel[] viewModels = GetPathViewModels(string.Empty, pageNumber, pageSize, out var totalItems); + FileSystemTreeItemPresentationModel[] viewModels = GetPathViewModels(string.Empty, skip, take, out var totalItems); PagedViewModel result = PagedViewModel(viewModels, totalItems); return await Task.FromResult(Ok(result)); @@ -30,12 +24,7 @@ public abstract class FileSystemTreeControllerBase : ManagementApiControllerBase protected async Task>> GetChildren(string path, int skip, int take) { - if (PaginationService.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize, out ProblemDetails? error) == false) - { - return BadRequest(error); - } - - FileSystemTreeItemPresentationModel[] viewModels = GetPathViewModels(path, pageNumber, pageSize, out var totalItems); + FileSystemTreeItemPresentationModel[] viewModels = GetPathViewModels(path, skip, take, out var totalItems); PagedViewModel result = PagedViewModel(viewModels, totalItems); return await Task.FromResult(Ok(result)); @@ -54,7 +43,7 @@ public abstract class FileSystemTreeControllerBase : ManagementApiControllerBase protected virtual bool DirectoryHasChildren(string path) => FileSystem.GetFiles(path).Any() || FileSystem.GetDirectories(path).Any(); - private FileSystemTreeItemPresentationModel[] GetPathViewModels(string path, long pageNumber, int pageSize, out long totalItems) + private FileSystemTreeItemPresentationModel[] GetPathViewModels(string path, int skip, int take, out long totalItems) { path = path.VirtualPathToSystemPath(); var allItems = GetDirectories(path) @@ -71,8 +60,8 @@ public abstract class FileSystemTreeControllerBase : ManagementApiControllerBase isFolder); return allItems - .Skip((int)(pageNumber * pageSize)) - .Take(pageSize) + .Skip(skip) + .Take(take) .Select(item => ViewModel(item.Path, item.IsFolder)) .ToArray(); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs index 11d2fc420e..08239688f6 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Tree/FolderTreeControllerBase.cs @@ -21,34 +21,19 @@ public abstract class FolderTreeControllerBase : NamedEntityTreeControlle protected void RenderFoldersOnly(bool foldersOnly) => _foldersOnly = foldersOnly; - protected override IEntitySlim[] GetPagedRootEntities(long pageNumber, int pageSize, out long totalItems) + protected override IEntitySlim[] GetPagedRootEntities(int skip, int take, out long totalItems) => GetEntities( - Constants.System.Root, - pageNumber, - pageSize, + Constants.System.RootKey, + skip, + take, out totalItems); - protected override IEntitySlim[] GetPagedChildEntities(Guid parentKey, long pageNumber, int pageSize, out long totalItems) - { - // EntityService is only able to get paged children by parent ID, so we must first map parent key to parent ID - Attempt parentId = EntityService.GetId(parentKey, FolderObjectType); - if (parentId.Success == false) - { - parentId = EntityService.GetId(parentKey, ItemObjectType); - if (parentId.Success == false) - { - // not much else we can do here but return nothing - totalItems = 0; - return Array.Empty(); - } - } - - return GetEntities( - parentId.Result, - pageNumber, - pageSize, + protected override IEntitySlim[] GetPagedChildEntities(Guid parentKey, int skip, int take, out long totalItems) => + GetEntities( + parentKey, + skip, + take, out totalItems); - } protected override TItem MapTreeItemViewModel(Guid? parentKey, IEntitySlim entity) { @@ -62,40 +47,40 @@ public abstract class FolderTreeControllerBase : NamedEntityTreeControlle return viewModel; } - private IEntitySlim[] GetEntities(int parentId, long pageNumber, int pageSize, out long totalItems) + private IEntitySlim[] GetEntities(Guid? parentKey, int skip, int take, out long totalItems) { totalItems = 0; - if (pageSize == 0) + if (take == 0) { totalItems = _foldersOnly - ? EntityService.CountChildren(parentId, FolderObjectType) - : EntityService.CountChildren(parentId, FolderObjectType) - + EntityService.CountChildren(parentId, ItemObjectType); + ? EntityService.CountChildren(parentKey, FolderObjectType) + : EntityService.CountChildren(parentKey, FolderObjectType) + + EntityService.CountChildren(parentKey, ItemObjectType); return Array.Empty(); } // EntityService is not able to paginate children of multiple item types, so we will only paginate the - // item type entities and always return all folders as part of the the first result page - IEntitySlim[] folderEntities = pageNumber == 0 - ? EntityService.GetChildren(parentId, FolderObjectType).OrderBy(c => c.Name).ToArray() + // item type entities and always return all folders as part of the the first result "page" i.e. when skip is 0 + IEntitySlim[] folderEntities = skip == 0 + ? EntityService.GetChildren(parentKey, FolderObjectType).OrderBy(c => c.Name).ToArray() : Array.Empty(); IEntitySlim[] itemEntities = _foldersOnly ? Array.Empty() : EntityService.GetPagedChildren( - parentId, + parentKey, ItemObjectType, - pageNumber, - pageSize, + skip, + take, out totalItems, ordering: ItemOrdering) .ToArray(); // the GetChildren for folders does not return an amount and does not get executed when beyond the first page // but the items still count towards the total, so add these to either 0 when only folders, or the out param from paged - totalItems += pageNumber == 0 + totalItems += skip == 0 ? folderEntities.Length - : EntityService.CountChildren(parentId, FolderObjectType); + : EntityService.CountChildren(parentKey, FolderObjectType); return folderEntities.Union(itemEntities).ToArray(); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Tree/UserStartNodeTreeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/Tree/UserStartNodeTreeControllerBase.cs index f72eff814b..1e82b6da35 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Tree/UserStartNodeTreeControllerBase.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Tree/UserStartNodeTreeControllerBase.cs @@ -35,14 +35,14 @@ public abstract class UserStartNodeTreeControllerBase : EntityTreeControl protected void IgnoreUserStartNodesForDataType(Guid? dataTypeKey) => _dataTypeKey = dataTypeKey; - protected override IEntitySlim[] GetPagedRootEntities(long pageNumber, int pageSize, out long totalItems) + protected override IEntitySlim[] GetPagedRootEntities(int skip, int take, out long totalItems) => UserHasRootAccess() || IgnoreUserStartNodes() - ? base.GetPagedRootEntities(pageNumber, pageSize, out totalItems) + ? base.GetPagedRootEntities(skip, take, out totalItems) : CalculateAccessMap(() => _userStartNodeEntitiesService.RootUserAccessEntities(ItemObjectType, UserStartNodeIds), out totalItems); - protected override IEntitySlim[] GetPagedChildEntities(Guid parentKey, long pageNumber, int pageSize, out long totalItems) + protected override IEntitySlim[] GetPagedChildEntities(Guid parentKey, int skip, int take, out long totalItems) { - IEntitySlim[] children = base.GetPagedChildEntities(parentKey, pageNumber, pageSize, out totalItems); + IEntitySlim[] children = base.GetPagedChildEntities(parentKey, skip, take, out totalItems); return UserHasRootAccess() || IgnoreUserStartNodes() ? children : CalculateAccessMap(() => _userStartNodeEntitiesService.ChildUserAccessEntities(children, UserStartNodePaths), out totalItems); diff --git a/src/Umbraco.Cms.Api.Management/Services/Paging/PaginationService.cs b/src/Umbraco.Cms.Api.Management/Services/Paging/PaginationService.cs deleted file mode 100644 index 3800b3b5dc..0000000000 --- a/src/Umbraco.Cms.Api.Management/Services/Paging/PaginationService.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; - -namespace Umbraco.Cms.Api.Management.Services.Paging; - -// TODO: remove this class once EF core is in place with proper skip/take pagination implementation -// this service is used for converting skip/take to classic pagination with page number and page size. -// it is a temporary solution that should be removed once EF core is in place, thus we'll live -// with this code being statically referenced across multiple controllers. the alternative would be -// an injectable service, but that would require a greater clean-up effort later on. -internal static class PaginationService -{ - internal static bool ConvertSkipTakeToPaging(int skip, int take, out long pageNumber, out int pageSize, out ProblemDetails? error) - { - 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; - error = 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", - }; - return false; - } - - pageSize = take; - pageNumber = take == 0 ? 0 : skip / take; - error = null; - return true; - } -} diff --git a/src/Umbraco.Core/Constants-System.cs b/src/Umbraco.Core/Constants-System.cs index 36db06d383..a94a1cd583 100644 --- a/src/Umbraco.Core/Constants-System.cs +++ b/src/Umbraco.Core/Constants-System.cs @@ -28,6 +28,11 @@ public static partial class Constants /// public const int RecycleBinContent = -20; + /// + /// The GUId identifier for content's recycle bin. + /// + public static readonly Guid RecycleBinContentKey = new("0F582A79-1E41-4CF0-BFA0-76340651891A"); + /// /// The string identifier for content's recycle bin. /// @@ -48,6 +53,11 @@ public static partial class Constants /// public const int RecycleBinMedia = -21; + /// + /// The GUID identifier for media's recycle bin. + /// + public static readonly Guid RecycleBinMediaKey = new("BF7C7CBC-952F-4518-97A2-69E9C7B33842"); + /// /// The string identifier for media's recycle bin. /// diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs index bf7cf3d6fa..d9c96a884d 100644 --- a/src/Umbraco.Core/Services/EntityService.cs +++ b/src/Umbraco.Core/Services/EntityService.cs @@ -303,6 +303,20 @@ public class EntityService : RepositoryService, IEntityService } } + public IEnumerable GetChildren(Guid? key, UmbracoObjectTypes objectType) + { + using ICoreScope scope = ScopeProvider.CreateCoreScope(); + + if (ResolveKey(key, objectType, out int parentId) is false) + { + return Enumerable.Empty(); + } + + IEnumerable children = GetChildren(parentId, objectType); + + return children; + } + /// public virtual IEnumerable GetDescendants(int id) { @@ -344,6 +358,38 @@ public class EntityService : RepositoryService, IEntityService Ordering? ordering = null) => GetPagedChildren(id, objectType, pageIndex, pageSize, false, filter, ordering, out totalRecords); + public IEnumerable GetPagedChildren( + Guid? key, + UmbracoObjectTypes objectType, + int skip, + int take, + out long totalRecords, + IQuery? filter = null, + Ordering? ordering = null) + { + using ICoreScope scope = ScopeProvider.CreateCoreScope(); + + if (ResolveKey(key, objectType, out int parentId) is false) + { + totalRecords = 0; + return Enumerable.Empty(); + } + + PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize); + + IEnumerable children = GetPagedChildren( + parentId, + objectType, + pageNumber, + pageSize, + out totalRecords, + filter, + ordering); + + scope.Complete(); + return children; + } + /// public IEnumerable GetPagedTrashedChildren( int id, @@ -355,6 +401,39 @@ public class EntityService : RepositoryService, IEntityService Ordering? ordering = null) => GetPagedChildren(id, objectType, pageIndex, pageSize, true, filter, ordering, out totalRecords); + IEnumerable GetPagedTrashedChildren( + Guid? key, + UmbracoObjectTypes objectType, + int skip, + int take, + out long totalRecords, + IQuery? filter = null, + Ordering? ordering = null) + { + using ICoreScope scope = ScopeProvider.CreateCoreScope(); + + if (ResolveKey(key, objectType, out int parentId) is false) + { + totalRecords = 0; + return Enumerable.Empty(); + } + + PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize); + + IEnumerable children = GetPagedChildren( + parentId, + objectType, + pageNumber, + pageSize, + true, + filter, + ordering, + out totalRecords); + + scope.Complete(); + return children; + } + /// public IEnumerable GetPagedDescendants( int id, @@ -558,6 +637,35 @@ public class EntityService : RepositoryService, IEntityService } } + public int CountChildren(Guid? key, UmbracoObjectTypes objectType, IQuery? filter = null) + { + using ICoreScope scope = ScopeProvider.CreateCoreScope(); + + if (ResolveKey(key, objectType, out var parentId) is false) + { + return 0; + } + + var count = CountChildren(parentId, objectType, filter); + + scope.Complete(); + return count; + } + + private bool ResolveKey(Guid? key, UmbracoObjectTypes objectType, out int id) + { + // We have to explicitly check for "root key" since this value is null, and GetId does not accept null. + if (key == Constants.System.RootKey) + { + id = Constants.System.Root; + return true; + } + + Attempt parentIdAttempt = GetId(key!.Value, objectType); + id = parentIdAttempt.Result; + return parentIdAttempt.Success; + } + // gets the object type, throws if not supported private UmbracoObjectTypes GetObjectType(Type? type) { diff --git a/src/Umbraco.Core/Services/IEntityService.cs b/src/Umbraco.Core/Services/IEntityService.cs index 40a7567cdd..ad64b7f2ac 100644 --- a/src/Umbraco.Core/Services/IEntityService.cs +++ b/src/Umbraco.Core/Services/IEntityService.cs @@ -183,6 +183,11 @@ public interface IEntityService /// The object type of the children. IEnumerable GetChildren(int id, UmbracoObjectTypes objectType); + IEnumerable GetChildren(Guid? key, UmbracoObjectTypes objectType) + { + return Array.Empty(); + } + /// /// Gets the descendants of an entity. /// @@ -196,6 +201,19 @@ public interface IEntityService /// The object type of the descendants. IEnumerable GetDescendants(int id, UmbracoObjectTypes objectType); + IEnumerable GetPagedChildren( + Guid? key, + UmbracoObjectTypes objectType, + int skip, + int take, + out long totalRecords, + IQuery? filter = null, + Ordering? ordering = null) + { + totalRecords = 0; + return Array.Empty(); + } + /// /// Gets children of an entity. /// @@ -224,6 +242,22 @@ public interface IEntityService return Array.Empty(); } + /// + /// Gets children of an entity. + /// + IEnumerable GetPagedTrashedChildren( + Guid? key, + UmbracoObjectTypes objectType, + int skip, + int take, + out long totalRecords, + IQuery? filter = null, + Ordering? ordering = null) + { + totalRecords = 0; + return Array.Empty(); + } + /// /// Gets descendants of an entity. /// @@ -319,4 +353,6 @@ public interface IEntityService /// Counts the children of an entity /// int CountChildren(int id, UmbracoObjectTypes objectType, IQuery? filter = null); + + public int CountChildren(Guid? key, UmbracoObjectTypes objectType, IQuery? filter = null) => 0; } diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs index 935dc4cf5b..293155d55a 100644 --- a/src/Umbraco.Core/Services/IMemberService.cs +++ b/src/Umbraco.Core/Services/IMemberService.cs @@ -31,6 +31,41 @@ public interface IMemberService : IMembershipMemberService, IContentServiceBase< string? memberTypeAlias = null, string filter = ""); + /// + /// Gets a list of paged objects + /// + /// An can be of type + /// Amount to skip. + /// Amount to take. + /// Total number of records found (out) + /// Field to order by + /// Direction to order by + /// + /// Search text filter + /// + /// + /// + IEnumerable GetAll( + int skip, + int take, + out long totalRecords, + string orderBy, + Direction orderDirection, + string? memberTypeAlias = null, + string filter = "") + { + PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize); + + return GetAll( + pageNumber, + pageSize, + out totalRecords, + orderBy, + orderDirection, + memberTypeAlias, + filter); + } + /// /// Gets a list of paged objects /// diff --git a/src/Umbraco.Core/Services/IRedirectUrlService.cs b/src/Umbraco.Core/Services/IRedirectUrlService.cs index f1897053f0..f835820b3c 100644 --- a/src/Umbraco.Core/Services/IRedirectUrlService.cs +++ b/src/Umbraco.Core/Services/IRedirectUrlService.cs @@ -78,6 +78,20 @@ public interface IRedirectUrlService : IService /// The redirect URLs. IEnumerable GetAllRedirectUrls(long pageIndex, int pageSize, out long total); + /// + /// Gets all redirect URLs. + /// + /// Amount to skip. + /// Amount to take. + /// The total count of redirect URLs. + /// The redirect URLs. + IEnumerable GetAllRedirectUrls(int skip, int take, out long total) + { + PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize); + + return GetAllRedirectUrls(pageNumber, pageSize, out total); + } + /// /// Gets all redirect URLs below a given content item. /// @@ -97,4 +111,19 @@ public interface IRedirectUrlService : IService /// The total count of redirect URLs. /// The redirect URLs. IEnumerable SearchRedirectUrls(string searchTerm, long pageIndex, int pageSize, out long total); + + /// + /// Searches for all redirect URLs that contain a given search term in their URL property. + /// + /// The term to search for. + /// Amount to skip. + /// Amount to take. + /// The total count of redirect URLs. + /// The redirect URLs. + IEnumerable SearchRedirectUrls(string searchTerm, int skip, int take, out long total) + { + PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize); + + return GetAllRedirectUrls(pageNumber, pageSize, out total); + } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index c2efc6d3c2..6341da03d3 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -274,14 +274,14 @@ internal class DatabaseDataCreator _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { - NodeId = -20, + NodeId = Constants.System.RecycleBinContent, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-20", SortOrder = 0, - UniqueId = new Guid("0F582A79-1E41-4CF0-BFA0-76340651891A"), + UniqueId = Constants.System.RecycleBinContentKey, Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.ContentRecycleBin, CreateDate = DateTime.Now, @@ -289,14 +289,14 @@ internal class DatabaseDataCreator _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { - NodeId = -21, + NodeId = Constants.System.RecycleBinMedia, Trashed = false, ParentId = -1, UserId = -1, Level = 0, Path = "-1,-21", SortOrder = 0, - UniqueId = new Guid("BF7C7CBC-952F-4518-97A2-69E9C7B33842"), + UniqueId = Constants.System.RecycleBinMediaKey, Text = "Recycle Bin", NodeObjectType = Constants.ObjectTypes.MediaRecycleBin, CreateDate = DateTime.Now,