From 0e1d8a3564d145e1339a7dc2148c84f1ddfa0ed0 Mon Sep 17 00:00:00 2001 From: yv01p Date: Tue, 23 Dec 2025 19:35:43 +0000 Subject: [PATCH] feat(core): add IContentPublishOperationService interface for Phase 5 Defines interface for content publishing operations: - Publish/Unpublish operations - Scheduled publishing (release/expiration) - Schedule management - Path checks (IsPathPublishable/IsPathPublished) - Workflow (SendToPublication) - Published content queries Part of ContentService refactoring Phase 5 - extracting ~1,500 lines of publishing logic into a dedicated service. Named IContentPublishOperationService to avoid collision with existing IContentPublishingService (API-layer orchestrator). Includes CommitDocumentChanges as [EditorBrowsable(Advanced)] to support orchestration scenarios (e.g., MoveToRecycleBin unpublishes before moving). Follows established pattern from Phases 1-4: - Extends IService - Implementation will inherit from ContentServiceBase - Additive-only versioning policy --- .../IContentPublishOperationService.cs | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 src/Umbraco.Core/Services/IContentPublishOperationService.cs diff --git a/src/Umbraco.Core/Services/IContentPublishOperationService.cs b/src/Umbraco.Core/Services/IContentPublishOperationService.cs new file mode 100644 index 0000000000..9c173d06f9 --- /dev/null +++ b/src/Umbraco.Core/Services/IContentPublishOperationService.cs @@ -0,0 +1,213 @@ +// src/Umbraco.Core/Services/IContentPublishOperationService.cs +using System.ComponentModel; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Persistence.Querying; + +namespace Umbraco.Cms.Core.Services; + +/// +/// Service for content publishing operations (publish, unpublish, scheduled publishing, branch publishing). +/// +/// +/// +/// 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 5). +/// It extracts publishing operations into a focused, testable service. +/// +/// +/// Note: This interface is named IContentPublishOperationService to avoid +/// collision with the existing IContentPublishingService which is an API-layer orchestrator. +/// +/// +/// 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. +/// +/// +public interface IContentPublishOperationService : IService +{ + #region Publishing + + /// + /// Publishes a document. + /// + /// The document to publish. + /// The cultures to publish. Use "*" for all cultures or specific culture codes. + /// The identifier of the user performing the action. + /// The publish result indicating success or failure. + /// + /// When a culture is being published, it includes all varying values along with all invariant values. + /// Wildcards (*) can be used as culture identifier to publish all cultures. + /// An empty array (or a wildcard) can be passed for culture invariant content. + /// Fires ContentPublishingNotification (cancellable) before publish and ContentPublishedNotification after. + /// + PublishResult Publish(IContent content, string[] cultures, int userId = Constants.Security.SuperUserId); + + /// + /// Publishes a document branch. + /// + /// The root document of the branch. + /// Options for force publishing unpublished or re-publishing unchanged content. + /// The cultures to publish. + /// The identifier of the user performing the operation. + /// Results for each document in the branch. + /// The root of the branch is always published, regardless of . + IEnumerable PublishBranch(IContent content, PublishBranchFilter publishBranchFilter, string[] cultures, int userId = Constants.Security.SuperUserId); + + #endregion + + #region Unpublishing + + /// + /// Unpublishes a document. + /// + /// The document to unpublish. + /// The culture to unpublish, or "*" for all cultures. + /// The identifier of the user performing the action. + /// The publish result indicating success or failure. + /// + /// By default, unpublishes the document as a whole, but it is possible to specify a culture. + /// If the content type is variant, culture can be either '*' or an actual culture. + /// If the content type is invariant, culture can be either '*' or null or empty. + /// Fires ContentUnpublishingNotification (cancellable) before and ContentUnpublishedNotification after. + /// + PublishResult Unpublish(IContent content, string? culture = "*", int userId = Constants.Security.SuperUserId); + + #endregion + + #region Document Changes (Advanced API) + + /// + /// Commits pending document publishing/unpublishing changes. + /// + /// The document with pending publish state changes. + /// The identifier of the user performing the action. + /// Optional state dictionary for notification propagation across orchestrated operations. + /// The publish result indicating success or failure. + /// + /// + /// This is an advanced API. Most consumers should use or + /// instead. + /// + /// + /// Call this after setting to + /// or . + /// + /// + /// This method is exposed for orchestration scenarios where publish/unpublish must be coordinated + /// with other operations (e.g., MoveToRecycleBin unpublishes before moving). + /// + /// + [EditorBrowsable(EditorBrowsableState.Advanced)] + PublishResult CommitDocumentChanges(IContent content, int userId = Constants.Security.SuperUserId, IDictionary? notificationState = null); + + #endregion + + #region Scheduled Publishing + + /// + /// Publishes and unpublishes scheduled documents. + /// + /// The date to check schedules against. + /// Results for each processed document. + IEnumerable PerformScheduledPublish(DateTime date); + + /// + /// Gets documents having an expiration date before (lower than, or equal to) a specified date. + /// + /// The date to check against. + /// Documents scheduled for expiration. + IEnumerable GetContentForExpiration(DateTime date); + + /// + /// Gets documents having a release date before (lower than, or equal to) a specified date. + /// + /// The date to check against. + /// Documents scheduled for release. + IEnumerable GetContentForRelease(DateTime date); + + #endregion + + #region Schedule Management + + /// + /// Gets publish/unpublish schedule for a content node by integer id. + /// + /// Id of the content to load schedule for. + /// The content schedule collection. + ContentScheduleCollection GetContentScheduleByContentId(int contentId); + + /// + /// Gets publish/unpublish schedule for a content node by GUID. + /// + /// Key of the content to load schedule for. + /// The content schedule collection. + ContentScheduleCollection GetContentScheduleByContentId(Guid contentId); + + /// + /// Persists publish/unpublish schedule for a content node. + /// + /// The content item. + /// The schedule to persist. + void PersistContentSchedule(IContent content, ContentScheduleCollection contentSchedule); + + /// + /// Gets a dictionary of content Ids and their matching content schedules. + /// + /// The content keys. + /// A dictionary with nodeId and an IEnumerable of matching ContentSchedules. + IDictionary> GetContentSchedulesByIds(Guid[] keys); + + #endregion + + #region Path Checks + + /// + /// Gets a value indicating whether a document is path-publishable. + /// + /// The content to check. + /// True if all ancestors are published. + /// A document is path-publishable when all its ancestors are published. + bool IsPathPublishable(IContent content); + + /// + /// Gets a value indicating whether a document is path-published. + /// + /// The content to check. + /// True if all ancestors and the document itself are published. + /// A document is path-published when all its ancestors, and the document itself, are published. + bool IsPathPublished(IContent? content); + + #endregion + + #region Workflow + + /// + /// Saves a document and raises the "sent to publication" events. + /// + /// The content to send to publication. + /// The identifier of the user issuing the send to publication. + /// True if sending publication was successful otherwise false. + /// + /// Fires ContentSendingToPublishNotification (cancellable) before and ContentSentToPublishNotification after. + /// + bool SendToPublication(IContent? content, int userId = Constants.Security.SuperUserId); + + #endregion + + #region Published Content Queries + + /// + /// Gets published children of a parent content item. + /// + /// Id of the parent to retrieve children from. + /// Published child content items, ordered by sort order. + IEnumerable GetPublishedChildren(int id); + + #endregion +}