From 1a48319575bff49dd9d72f74124e701daada9c0b Mon Sep 17 00:00:00 2001 From: yv01p Date: Tue, 23 Dec 2025 17:00:27 +0000 Subject: [PATCH] feat(core): add IContentMoveOperationService interface for Phase 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defines interface for Move, Copy, Sort, and Recycle Bin operations. MoveToRecycleBin deliberately excluded as it requires facade orchestration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Services/IContentMoveOperationService.cs | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 src/Umbraco.Core/Services/IContentMoveOperationService.cs diff --git a/src/Umbraco.Core/Services/IContentMoveOperationService.cs b/src/Umbraco.Core/Services/IContentMoveOperationService.cs new file mode 100644 index 0000000000..5f82f7a8f8 --- /dev/null +++ b/src/Umbraco.Core/Services/IContentMoveOperationService.cs @@ -0,0 +1,162 @@ +// src/Umbraco.Core/Services/IContentMoveOperationService.cs +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Persistence.Querying; + +namespace Umbraco.Cms.Core.Services; + +/// +/// Service for content move, copy, sort, and recycle bin operations. +/// +/// +/// +/// Implementation Note: Do not implement this interface directly. +/// Instead, inherit from which provides required +/// infrastructure (scoping, repository access, auditing). Direct implementation +/// without this base class will result in missing functionality. +/// +/// +/// This interface is part of the ContentService refactoring initiative (Phase 4). +/// It extracts move/copy/sort operations into a focused, testable service. +/// +/// +/// Note: MoveToRecycleBin is NOT part of this interface because +/// it orchestrates multiple services (unpublish + move) and belongs in the facade. +/// +/// +/// Versioning Policy: This interface follows additive-only changes. +/// New methods may be added with default implementations. Existing methods will not +/// be removed or have signatures changed without a 2 major version deprecation period. +/// +/// +/// Version History: +/// +/// v1.0 (Phase 4): Initial interface with Move, Copy, Sort, RecycleBin operations +/// +/// +/// +/// 1.0 +public interface IContentMoveOperationService : IService +{ + // Note: #region blocks kept for consistency with existing Umbraco interface patterns + + #region Move Operations + + /// + /// Moves content to a new parent. + /// + /// The content to move. + /// The target parent id, or -1 for root. + /// The user performing the operation. + /// The operation result. + /// + /// If parentId is the recycle bin (-20), this method delegates to MoveToRecycleBin + /// behavior (should be called via ContentService facade instead). + /// Fires (cancellable) before move + /// and after successful move. + /// + OperationResult Move(IContent content, int parentId, int userId = Constants.Security.SuperUserId); + + #endregion + + #region Recycle Bin Operations + + /// + /// Empties the content recycle bin. + /// + /// The user performing the operation. + /// The operation result. + /// + /// Fires (cancellable) before emptying + /// and after successful empty. + /// Content with active relations may be skipped if DisableDeleteWhenReferenced is configured. + /// + OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId); + + /// + /// Empties the content recycle bin asynchronously. + /// + /// The user key performing the operation. + /// The operation result. + Task EmptyRecycleBinAsync(Guid userId); + + /// + /// Checks whether there is content in the recycle bin. + /// + /// True if the recycle bin has content; otherwise false. + bool RecycleBinSmells(); + + /// + /// Gets paged content from the recycle bin. + /// + /// Zero-based page index. + /// Page size. + /// Output: total number of records in recycle bin. + /// Optional filter query. + /// Optional ordering (defaults to Path). + /// Paged content from the recycle bin. + IEnumerable GetPagedContentInRecycleBin( + long pageIndex, + int pageSize, + out long totalRecords, + IQuery? filter = null, + Ordering? ordering = null); + + #endregion + + #region Copy Operations + + /// + /// Copies content to a new parent, including all descendants. + /// + /// The content to copy. + /// The target parent id. + /// Whether to create a relation to the original. + /// The user performing the operation. + /// The copied content, or null if cancelled. + /// + /// Fires (cancellable) before each copy + /// and after each successful copy. + /// The copy is not published regardless of the original's published state. + /// + IContent? Copy(IContent content, int parentId, bool relateToOriginal, int userId = Constants.Security.SuperUserId); + + /// + /// Copies content to a new parent. + /// + /// The content to copy. + /// The target parent id. + /// Whether to create a relation to the original. + /// Whether to copy descendants recursively. + /// The user performing the operation. + /// The copied content, or null if cancelled. + IContent? Copy(IContent content, int parentId, bool relateToOriginal, bool recursive, int userId = Constants.Security.SuperUserId); + + #endregion + + #region Sort Operations + + /// + /// Sorts content items by updating their SortOrder. + /// + /// The content items in desired order. + /// The user performing the operation. + /// The operation result. + /// + /// Fires (cancellable) and + /// (cancellable) before sorting. + /// Fires , + /// , and + /// (if any were published) after. + /// + OperationResult Sort(IEnumerable items, int userId = Constants.Security.SuperUserId); + + /// + /// Sorts content items by id in the specified order. + /// + /// The content ids in desired order. + /// The user performing the operation. + /// The operation result. + OperationResult Sort(IEnumerable? ids, int userId = Constants.Security.SuperUserId); + + #endregion +}