diff --git a/src/Umbraco.Core/Models/ContentEditing/PublishContent.cs b/src/Umbraco.Core/Models/ContentEditing/PublishContent.cs new file mode 100644 index 0000000000..ba6d8d2f6f --- /dev/null +++ b/src/Umbraco.Core/Models/ContentEditing/PublishContent.cs @@ -0,0 +1,16 @@ +using System.Runtime.Serialization; + +namespace Umbraco.Cms.Core.Models.ContentEditing; + +/// +/// Used to publish content and variants +/// +[DataContract(Name = "publish", Namespace = "")] +public class PublishContent +{ + [DataMember(Name = "id")] + public int Id { get; set; } + + [DataMember(Name = "cultures")] + public string[]? Cultures { get; set; } +} diff --git a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs index c9bc07457a..944068114a 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ContentController.cs @@ -168,8 +168,8 @@ public class ContentController : ContentControllerBase authorizationService, contentVersionService, StaticServiceProvider.Instance.GetRequiredService()) - { - } + { + } public object? Domains { get; private set; } @@ -1950,6 +1950,7 @@ public class ContentController : ContentControllerBase } PublishResult publishResult = _contentService.SaveAndPublish(foundContent, userId: _backofficeSecurityAccessor.BackOfficeSecurity?.GetUserId().Result ?? 0); + if (publishResult.Success == false) { var notificationModel = new SimpleNotificationModel(); @@ -1960,6 +1961,56 @@ public class ContentController : ContentControllerBase return Ok(); } + /// + /// Publishes a document with a given ID and cultures. + /// + /// + /// + /// + /// The EnsureUserPermissionForContent attribute will deny access to this method if the current user + /// does not have Publish access to this node. + /// + [Authorize(Policy = AuthorizationPolicies.ContentPermissionPublishById)] + public IActionResult PostPublishByIdAndCulture(PublishContent model) + { + var languageCount = _allLangs.Value.Count(); + + // If there is no culture specified or the cultures specified are equal to the total amount of languages, publish the content in all cultures. + if (model.Cultures == null || !model.Cultures.Any() || model.Cultures.Length == languageCount) + { + return PostPublishById(model.Id); + } + + IContent? foundContent = GetObjectFromRequest(() => _contentService.GetById(model.Id)); + + if (foundContent == null) + { + return HandleContentNotFound(model.Id); + } + + var results = new Dictionary(); + + foreach (var culture in model.Cultures) + { + PublishResult publishResult = _contentService.SaveAndPublish(foundContent, culture, _backofficeSecurityAccessor.BackOfficeSecurity?.GetUserId().Result ?? 0); + results[culture] = publishResult; + } + + if (results.Any(x => x.Value.Success == false)) + { + var notificationModel = new SimpleNotificationModel(); + + foreach (var culture in results.Where(x => x.Value.Success == false)) + { + AddMessageForPublishStatus(new[] { culture.Value }, notificationModel); + } + + return ValidationProblem(notificationModel); + } + + return Ok(); + } + [HttpDelete] [HttpPost] public IActionResult DeleteBlueprint(int id) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js index 7e6c6658e5..b3218b2c7f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js @@ -278,7 +278,8 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { * alert("node wasnt unpublished:" + err.data.Message); * }); * - * @param {Int} id the ID of the node to unpublish + * @param {Int} id the ID of the node to unpublish. + * @param {array} cultures the cultures to unpublish. * @returns {Promise} resourcePromise object. * */ @@ -1086,23 +1087,31 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { * * * @param {Int} id The ID of the conten to publish + * @param {array} cultures the cultures to publish. * @returns {Promise} resourcePromise object containing the published content item. * */ - publishById: function (id) { - + publishById: function (id, cultures) { if (!id) { throw "id cannot be null"; } - return umbRequestHelper.resourcePromise( - $http.post( + if (!cultures) { + return umbRequestHelper.resourcePromise( + $http.post( umbRequestHelper.getApiUrl( - "contentApiBaseUrl", - "PostPublishById", - [{ id: id }])), - 'Failed to publish content with id ' + id); - + "contentApiBaseUrl", + "PostPublishById"), { id: id }), + 'Failed to publish content with id ' + id); + } + else { + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "PostPublishByIdAndCulture"), { id: id, cultures: cultures }), + 'Failed to publish content with id ' + id); + } }, /**