diff --git a/src/Umbraco.Core/ContentExtensions.cs b/src/Umbraco.Core/ContentExtensions.cs index 5db080f3f3..9fcc12bc10 100644 --- a/src/Umbraco.Core/ContentExtensions.cs +++ b/src/Umbraco.Core/ContentExtensions.cs @@ -67,21 +67,7 @@ namespace Umbraco.Core content.WasCulturePublished(x)) // but was published before .ToList(); } - - /// - /// Returns true if this entity was just published as part of a recent save operation (i.e. it wasn't previously published) - /// - /// - /// - /// - /// This is helpful for determining if the published event will execute during the saved event for a content item. - /// - internal static bool JustPublished(this IContent entity) - { - var dirty = (IRememberBeingDirty)entity; - return dirty.WasPropertyDirty("Published") && entity.Published; - } - + #endregion /// diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs index 16b28e088a..93f2b08482 100644 --- a/src/Umbraco.Core/Models/Content.cs +++ b/src/Umbraco.Core/Models/Content.cs @@ -420,7 +420,7 @@ namespace Umbraco.Core.Models /// /// New ContentType for this content /// Leaves PropertyTypes intact after change - public void ChangeContentType(IContentType contentType) + internal void ChangeContentType(IContentType contentType) { ContentTypeId = contentType.Id; ContentType = new SimpleContentType(contentType); @@ -437,7 +437,7 @@ namespace Umbraco.Core.Models /// /// New ContentType for this content /// Boolean indicating whether to clear PropertyTypes upon change - public void ChangeContentType(IContentType contentType, bool clearProperties) + internal void ChangeContentType(IContentType contentType, bool clearProperties) { if(clearProperties) { diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index ca1152a9a4..89749da7e2 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -376,7 +376,7 @@ namespace Umbraco.Core.Models #region Validation /// - public virtual Property[] ValidateProperties(string culture = "*") + public Property[] ValidateProperties(string culture = "*") { var alsoInvariant = culture != null && culture != "*"; diff --git a/src/Umbraco.Core/Models/IContent.cs b/src/Umbraco.Core/Models/IContent.cs index ee38f613a3..1d85a735b5 100644 --- a/src/Umbraco.Core/Models/IContent.cs +++ b/src/Umbraco.Core/Models/IContent.cs @@ -79,7 +79,7 @@ namespace Umbraco.Core.Models /// and the content published name for this culture is non-null. It becomes non-published /// whenever values for this culture are unpublished. /// A culture becomes published as soon as PublishCulture has been invoked, - /// even though the document might now have been saved yet (and can have no identity). + /// even though the document might not have been saved yet (and can have no identity). /// Does not support the '*' wildcard (returns false). /// bool IsCulturePublished(string culture); @@ -137,23 +137,6 @@ namespace Umbraco.Core.Models /// IEnumerable EditedCultures { get; } - // TODO: these two should move to some kind of service - - /// - /// Changes the for the current content object - /// - /// New ContentType for this content - /// Leaves PropertyTypes intact after change - void ChangeContentType(IContentType contentType); - - /// - /// Changes the for the current content object and removes PropertyTypes, - /// which are not part of the new ContentType. - /// - /// New ContentType for this content - /// Boolean indicating whether to clear PropertyTypes upon change - void ChangeContentType(IContentType contentType, bool clearProperties); - /// /// Creates a deep clone of the current entity with its identity/alias and it's property identities reset /// diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 7fb7450b46..ad97ba2ddc 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -336,29 +336,47 @@ namespace Umbraco.Core.Services /// /// /// By default, publishes all variations of the document, but it is possible to specify a culture to be published. - /// When a culture is being published, it includes all varying values along with all invariant values. For - /// anything more complicated, see . + /// When a culture is being published, it includes all varying values along with all invariant values. /// The document is *always* saved, even when publishing fails. /// If the content type is variant, then culture can be either '*' or an actual culture, but neither 'null' nor /// 'empty'. If the content type is invariant, then culture can be either '*' or null or empty. /// + /// + /// + /// + /// + /// PublishResult SaveAndPublish(IContent content, string culture = "*", int userId = 0, bool raiseEvents = true); /// - /// Saves and publishes a publishing document. + /// Saves and publishes a document. /// /// - /// A publishing document is a document with values that are being published, i.e. - /// that have been published or cleared via and - /// . - /// When one needs to publish or unpublish a single culture, or all cultures, using - /// and is the way to go. But if one needs to, say, publish two cultures and unpublish a third - /// one, in one go, then one needs to invoke and - /// on the content itself - this prepares the content, but does not commit anything - and then, invoke - /// to actually commit the changes to the database. + /// By default, publishes all variations of the document, but it is possible to specify a culture to be published. + /// When a culture is being published, it includes all varying values along with all invariant values. /// The document is *always* saved, even when publishing fails. /// - PublishResult SavePublishing(IContent content, int userId = 0, bool raiseEvents = true); + /// + /// The cultures to publish. + /// + /// + /// + PublishResult SaveAndPublish(IContent content, string[] cultures, int userId = 0, bool raiseEvents = true); + + /// + /// Expert: Saves a document and publishes/unpublishes any pending publishing changes made to the document. + /// + /// + /// Pending publishing/unpublishing changes on a document are made with calls to and + /// . + /// When publishing or unpublishing a single culture, or all cultures, use + /// and . But if the flexibility to both publish and unpublish in a single operation is required + /// then this method needs to be used in combination with and + /// on the content itself - this prepares the content, but does not commit anything - and then, invoke + /// to actually commit the changes to the database. + /// The document is *always* saved, even when publishing fails. + /// + PublishResult CommitDocumentChanges(IContent content, int userId = 0, bool raiseEvents = true); /// /// Saves and publishes a document branch. diff --git a/src/Umbraco.Core/Services/Implement/ContentService.cs b/src/Umbraco.Core/Services/Implement/ContentService.cs index c5745090f9..404adeea72 100644 --- a/src/Umbraco.Core/Services/Implement/ContentService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentService.cs @@ -857,7 +857,7 @@ namespace Umbraco.Core.Services.Implement var publishedState = content.PublishedState; if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished) - throw new InvalidOperationException($"Cannot save-and-publish (un)publishing content, use the dedicated {nameof(SavePublishing)} method."); + throw new InvalidOperationException($"Cannot save-and-publish (un)publishing content, use the dedicated {nameof(CommitDocumentChanges)} method."); // cannot accept invariant (null or empty) culture for variant content type // cannot accept a specific culture for invariant content type (but '*' is ok) @@ -891,7 +891,31 @@ namespace Umbraco.Core.Services.Implement // finally, "save publishing" // what happens next depends on whether the content can be published or not - return SavePublishing(content, userId, raiseEvents); + return CommitDocumentChanges(content, userId, raiseEvents); + } + + /// + public PublishResult SaveAndPublish(IContent content, string[] cultures, int userId = 0, bool raiseEvents = true) + { + if (content == null) throw new ArgumentNullException(nameof(content)); + if (cultures == null) throw new ArgumentNullException(nameof(cultures)); + + var evtMsgs = EventMessagesFactory.Get(); + + var varies = content.ContentType.VariesByCulture(); + + if (cultures.Length == 0) + { + //no cultures specified and doesn't vary, so publish it, else nothing to publish + return !varies + ? SaveAndPublish(content, userId: userId, raiseEvents: raiseEvents) + : new PublishResult(PublishResultType.FailedPublishNothingToPublish, evtMsgs, content); + } + + if (cultures.Select(content.PublishCulture).Any(isValid => !isValid)) + return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, content); //fixme: no way to know which one failed? + + return CommitDocumentChanges(content, userId, raiseEvents); } /// @@ -903,7 +927,7 @@ namespace Umbraco.Core.Services.Implement var publishedState = content.PublishedState; if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished) - throw new InvalidOperationException($"Cannot save-and-publish (un)publishing content, use the dedicated {nameof(SavePublishing)} method."); + throw new InvalidOperationException($"Cannot save-and-publish (un)publishing content, use the dedicated {nameof(CommitDocumentChanges)} method."); // cannot accept invariant (null or empty) culture for variant content type // cannot accept a specific culture for invariant content type (but '*' is ok) @@ -938,22 +962,22 @@ namespace Umbraco.Core.Services.Implement } // finally, "save publishing" - return SavePublishing(content, userId); + return CommitDocumentChanges(content, userId); } /// - public PublishResult SavePublishing(IContent content, int userId = 0, bool raiseEvents = true) + public PublishResult CommitDocumentChanges(IContent content, int userId = 0, bool raiseEvents = true) { using (var scope = ScopeProvider.CreateScope()) { scope.WriteLock(Constants.Locks.ContentTree); - var result = SavePublishingInternal(scope, content, userId, raiseEvents); + var result = CommitDocumentChangesInternal(scope, content, userId, raiseEvents); scope.Complete(); return result; } } - private PublishResult SavePublishingInternal(IScope scope, IContent content, int userId = 0, bool raiseEvents = true, bool branchOne = false, bool branchRoot = false) + private PublishResult CommitDocumentChangesInternal(IScope scope, IContent content, int userId = 0, bool raiseEvents = true, bool branchOne = false, bool branchRoot = false) { var evtMsgs = EventMessagesFactory.Get(); PublishResult publishResult = null; @@ -961,7 +985,7 @@ namespace Umbraco.Core.Services.Implement // nothing set = republish it all if (content.PublishedState != PublishedState.Publishing && content.PublishedState != PublishedState.Unpublishing) - ((Content)content).PublishedState = PublishedState.Publishing; + ((Content)content).PublishedState = PublishedState.Publishing; //TODO: fix this https://github.com/umbraco/Umbraco-CMS/issues/4234 // state here is either Publishing or Unpublishing // (even though, Publishing to unpublish a culture may end up unpublishing everything) @@ -1217,7 +1241,7 @@ namespace Umbraco.Core.Services.Implement else if (!publishing) result = new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, d); else - result = SavePublishing(d, d.WriterId); + result = CommitDocumentChanges(d, d.WriterId); if (result.Success == false) Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); @@ -1261,7 +1285,7 @@ namespace Umbraco.Core.Services.Implement if (pendingCultures.Count > 0) { - result = SavePublishing(d, d.WriterId); + result = CommitDocumentChanges(d, d.WriterId); if (result.Success == false) Logger.Error(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result); yield return result; @@ -1495,7 +1519,7 @@ namespace Umbraco.Core.Services.Implement if (!publishCultures(document, culturesToPublish)) return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, document); - var result = SavePublishingInternal(scope, document, userId, branchOne: true, branchRoot: isRoot); + var result = CommitDocumentChangesInternal(scope, document, userId, branchOne: true, branchRoot: isRoot); if (result.Success) publishedDocuments.Add(document); return result; diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index 862925db2c..805c957a2e 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -704,20 +704,23 @@ namespace Umbraco.Tests.Models } [Test] + [Ignore("Need to reimplement this logic for v8")] public void Can_Change_ContentType_On_Content_And_Clear_Old_PropertyTypes() { - // Arrange - var contentType = MockedContentTypes.CreateTextPageContentType(); - var simpleContentType = MockedContentTypes.CreateSimpleContentType(); - var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); + throw new NotImplementedException(); - // Act - content.ChangeContentType(simpleContentType, true); + //// Arrange + //var contentType = MockedContentTypes.CreateTextPageContentType(); + //var simpleContentType = MockedContentTypes.CreateSimpleContentType(); + //var content = MockedContent.CreateTextpageContent(contentType, "Textpage", -1); - // Assert - Assert.That(content.Properties.Contains("author"), Is.True); - Assert.That(content.Properties.Contains("keywords"), Is.False); - Assert.That(content.Properties.Contains("description"), Is.False); + //// Act + //content.ChangeContentType(simpleContentType, true); + + //// Assert + //Assert.That(content.Properties.Contains("author"), Is.True); + //Assert.That(content.Properties.Contains("keywords"), Is.False); + //Assert.That(content.Properties.Contains("description"), Is.False); } [Test] diff --git a/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs b/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs index 4afd5e33eb..d2343d3dea 100644 --- a/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs +++ b/src/Umbraco.Tests/Services/ContentServicePublishBranchTests.cs @@ -264,9 +264,7 @@ namespace Umbraco.Tests.Services vRoot.SetValue("vp", "changed.es", "es"); ServiceContext.ContentService.Save(vRoot); // now root has drafts in all cultures - iv1.PublishCulture("de"); - iv1.PublishCulture("ru"); - ServiceContext.ContentService.SavePublishing(iv1); // now iv1 de and ru are published + ServiceContext.ContentService.SaveAndPublish(iv1, new []{"de", "ru"}); // now iv1 de and ru are published iv1.SetValue("ip", "changed"); iv1.SetValue("vp", "changed.de", "de"); @@ -345,10 +343,8 @@ namespace Umbraco.Tests.Services iv11.SetValue("vp", "iv11.es", "es"); ServiceContext.ContentService.Save(iv11); - iv11.PublishCulture("de"); iv11.SetCultureName("iv11.ru", "ru"); - iv11.PublishCulture("ru"); - ServiceContext.ContentService.SavePublishing(iv11); + ServiceContext.ContentService.SaveAndPublish(iv11, new []{"de", "ru"}); Assert.AreEqual("iv11.de", iv11.GetValue("vp", "de", published: true)); Assert.AreEqual("iv11.ru", iv11.GetValue("vp", "ru", published: true)); diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 017f1f50ec..3e21768f97 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -767,7 +767,7 @@ namespace Umbraco.Tests.Services Assert.IsTrue(content.IsCulturePublished(langUk.IsoCode)); Assert.IsFalse(content.WasCulturePublished(langUk.IsoCode)); //not persisted yet, will be false - var published = ServiceContext.ContentService.SavePublishing(content); + var published = ServiceContext.ContentService.SaveAndPublish(content, new[]{ langFr.IsoCode , langUk.IsoCode }); //re-get content = ServiceContext.ContentService.GetById(content.Id); Assert.IsTrue(published.Success); @@ -819,9 +819,8 @@ namespace Umbraco.Tests.Services IContent content = new Content("content", -1, contentType); content.SetCultureName("content-en", langGB.IsoCode); content.SetCultureName("content-fr", langFr.IsoCode); - content.PublishCulture(langGB.IsoCode); - content.PublishCulture(langFr.IsoCode); - Assert.IsTrue(ServiceContext.ContentService.SavePublishing(content).Success); + + Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content, new []{ langGB.IsoCode , langFr.IsoCode }).Success); //re-get content = ServiceContext.ContentService.GetById(content.Id); @@ -861,8 +860,7 @@ namespace Umbraco.Tests.Services IContent content = new Content("content", -1, contentType); content.SetCultureName("content-fr", langFr.IsoCode); - content.PublishCulture(langFr.IsoCode); - var published = ServiceContext.ContentService.SavePublishing(content); + var published = ServiceContext.ContentService.SaveAndPublish(content, langFr.IsoCode); //audit log will only show that french was published var lastLog = ServiceContext.AuditService.GetLogs(content.Id).Last(); Assert.AreEqual($"Published languages: French (France)", lastLog.Comment); @@ -870,8 +868,7 @@ namespace Umbraco.Tests.Services //re-get content = ServiceContext.ContentService.GetById(content.Id); content.SetCultureName("content-en", langGB.IsoCode); - content.PublishCulture(langGB.IsoCode); - published = ServiceContext.ContentService.SavePublishing(content); + published = ServiceContext.ContentService.SaveAndPublish(content, langGB.IsoCode); //audit log will only show that english was published lastLog = ServiceContext.AuditService.GetLogs(content.Id).Last(); Assert.AreEqual($"Published languages: English (United Kingdom)", lastLog.Comment); @@ -895,15 +892,12 @@ namespace Umbraco.Tests.Services IContent content = new Content("content", -1, contentType); content.SetCultureName("content-fr", langFr.IsoCode); content.SetCultureName("content-gb", langGB.IsoCode); - content.PublishCulture(langGB.IsoCode); - content.PublishCulture(langFr.IsoCode); - var published = ServiceContext.ContentService.SavePublishing(content); + var published = ServiceContext.ContentService.SaveAndPublish(content, new[] {langGB.IsoCode, langFr.IsoCode}); Assert.IsTrue(published.Success); //re-get content = ServiceContext.ContentService.GetById(content.Id); - content.UnpublishCulture(langFr.IsoCode); //unpublish non-mandatory lang - var unpublished = ServiceContext.ContentService.SavePublishing(content); + var unpublished = ServiceContext.ContentService.Unpublish(content, langFr.IsoCode); //audit log will only show that french was unpublished var lastLog = ServiceContext.AuditService.GetLogs(content.Id).Last(); Assert.AreEqual($"Unpublished languages: French (France)", lastLog.Comment); @@ -911,8 +905,7 @@ namespace Umbraco.Tests.Services //re-get content = ServiceContext.ContentService.GetById(content.Id); content.SetCultureName("content-en", langGB.IsoCode); - content.UnpublishCulture(langGB.IsoCode); //unpublish mandatory lang - unpublished = ServiceContext.ContentService.SavePublishing(content); + unpublished = ServiceContext.ContentService.Unpublish(content, langGB.IsoCode); //audit log will only show that english was published var logs = ServiceContext.AuditService.GetLogs(content.Id).ToList(); Assert.AreEqual($"Unpublished languages: English (United Kingdom)", logs[logs.Count - 2].Comment); @@ -927,8 +920,7 @@ namespace Umbraco.Tests.Services var content = contentService.GetById(NodeDto.NodeIdSeed + 2); // Act - content.PublishCulture(); - var published = contentService.SavePublishing(content, Constants.Security.SuperUserId); + var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(published.Success, Is.True); @@ -982,8 +974,7 @@ namespace Umbraco.Tests.Services Assert.AreEqual("Home", content.Name); content.Name = "foo"; - content.PublishCulture(); - var published = contentService.SavePublishing(content, Constants.Security.SuperUserId); + var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); Assert.That(published.Success, Is.True); Assert.That(content.Published, Is.True); @@ -1030,10 +1021,7 @@ namespace Umbraco.Tests.Services Assert.IsTrue(parentPublished.Success); Assert.IsTrue(parent.Published); - var contentCanPublishValues = content.PublishCulture(); - // content cannot publish values because they are invalid - Assert.IsFalse(contentCanPublishValues); Assert.IsNotEmpty(content.ValidateProperties()); // and therefore cannot be published, @@ -1061,7 +1049,7 @@ namespace Umbraco.Tests.Services content.SetCultureName("name-da", langDa.IsoCode); content.PublishCulture(langFr.IsoCode); - var result = ServiceContext.ContentService.SavePublishing(content); + var result = ServiceContext.ContentService.CommitDocumentChanges(content); Assert.IsTrue(result.Success); content = ServiceContext.ContentService.GetById(content.Id); Assert.IsTrue(content.IsCulturePublished(langFr.IsoCode)); @@ -1070,7 +1058,7 @@ namespace Umbraco.Tests.Services content.UnpublishCulture(langFr.IsoCode); content.PublishCulture(langDa.IsoCode); - result = ServiceContext.ContentService.SavePublishing(content); + result = ServiceContext.ContentService.CommitDocumentChanges(content); Assert.IsTrue(result.Success); Assert.AreEqual(PublishResultType.SuccessMixedCulture, result.Result); @@ -1149,12 +1137,10 @@ namespace Umbraco.Tests.Services contentService.Save(content); var parent = contentService.GetById(NodeDto.NodeIdSeed + 2); - parent.PublishCulture(); - var parentPublished = contentService.SavePublishing(parent, Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'NodeDto.NodeIdSeed + 3' + var parentPublished = contentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'NodeDto.NodeIdSeed + 3' // Act - content.PublishCulture(); - var published = contentService.SavePublishing(content, Constants.Security.SuperUserId); + var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(parentPublished.Success, Is.True); @@ -1192,12 +1178,10 @@ namespace Umbraco.Tests.Services contentService.Save(content, Constants.Security.SuperUserId); var parent = contentService.GetById(NodeDto.NodeIdSeed + 2); - parent.PublishCulture(); - var parentPublished = contentService.SavePublishing(parent, Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'NodeDto.NodeIdSeed + 3' + var parentPublished = contentService.SaveAndPublish(parent, userId: Constants.Security.SuperUserId);//Publish root Home node to enable publishing of 'NodeDto.NodeIdSeed + 3' // Act - content.PublishCulture(); - var published = contentService.SavePublishing(content, Constants.Security.SuperUserId); + var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(parentPublished.Success, Is.True); @@ -1249,8 +1233,7 @@ namespace Umbraco.Tests.Services var content = contentService.GetById(NodeDto.NodeIdSeed + 5); // Act - content.PublishCulture(); - var published = contentService.SavePublishing(content, Constants.Security.SuperUserId); + var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(published.Success, Is.False); @@ -1267,8 +1250,7 @@ namespace Umbraco.Tests.Services content.SetValue("author", "Barack Obama"); // Act - content.PublishCulture(); - var published = contentService.SavePublishing(content, Constants.Security.SuperUserId); + var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); // Assert Assert.That(content.HasIdentity, Is.True); @@ -1292,15 +1274,13 @@ namespace Umbraco.Tests.Services content.SetValue("author", "Barack Obama"); // Act - content.PublishCulture(); - var published = contentService.SavePublishing(content, Constants.Security.SuperUserId); + var published = contentService.SaveAndPublish(content, userId: Constants.Security.SuperUserId); var childContent = contentService.Create("Child", content.Id, "umbTextpage", Constants.Security.SuperUserId); // Reset all identity properties childContent.Id = 0; childContent.Path = null; ((Content)childContent).ResetIdentity(); - childContent.PublishCulture(); - var childPublished = contentService.SavePublishing(childContent, Constants.Security.SuperUserId); + var childPublished = contentService.SaveAndPublish(childContent, userId: Constants.Security.SuperUserId); // Assert Assert.That(content.HasIdentity, Is.True); @@ -1639,14 +1619,12 @@ namespace Umbraco.Tests.Services content1.PropertyValues(obj); content1.ResetDirtyProperties(false); ServiceContext.ContentService.Save(content1, Constants.Security.SuperUserId); - content1.PublishCulture(); - Assert.IsTrue(ServiceContext.ContentService.SavePublishing(content1, 0).Success); + Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content1, userId: 0).Success); var content2 = MockedContent.CreateBasicContent(contentType); content2.PropertyValues(obj); content2.ResetDirtyProperties(false); ServiceContext.ContentService.Save(content2, Constants.Security.SuperUserId); - content2.PublishCulture(); - Assert.IsTrue(ServiceContext.ContentService.SavePublishing(content2, 0).Success); + Assert.IsTrue(ServiceContext.ContentService.SaveAndPublish(content2, userId: 0).Success); var editorGroup = ServiceContext.UserService.GetUserGroupByAlias("editor"); editorGroup.StartContentId = content1.Id; @@ -2721,9 +2699,7 @@ namespace Umbraco.Tests.Services // act - content.PublishCulture(langFr.IsoCode); - content.PublishCulture(langUk.IsoCode); - contentService.SavePublishing(content); + contentService.SaveAndPublish(content, new[]{ langFr.IsoCode, langUk.IsoCode }); // both FR and UK have been published, // and content has been published, @@ -2827,8 +2803,7 @@ namespace Umbraco.Tests.Services // act // cannot just 'save' since we are changing what's published! - content.UnpublishCulture(langFr.IsoCode); - contentService.SavePublishing(content); + contentService.Unpublish(content, langFr.IsoCode); // content has been published, // the french culture is gone @@ -2919,7 +2894,7 @@ namespace Umbraco.Tests.Services // that HAS to be SavePublishing, because SaveAndPublish would just republish everything! - contentService.SavePublishing(content); + contentService.CommitDocumentChanges(content); // content has been re-published, // everything is back to what it was before being unpublished @@ -2959,8 +2934,7 @@ namespace Umbraco.Tests.Services // act - content.PublishCulture(langUk.IsoCode); - contentService.SavePublishing(content); + contentService.SaveAndPublish(content, langUk.IsoCode); content2 = contentService.GetById(content.Id); diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index ee056e38f0..5cbd83d236 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1148,7 +1148,6 @@ namespace Umbraco.Web.Editors /// Performs the publishing operation for a content item /// /// - /// /// /// /// if the content is variant this will return an array of cultures that will be published (passed validation rules) @@ -1197,10 +1196,12 @@ namespace Umbraco.Web.Editors if (canPublish) { + var culturesToPublish = cultureVariants.Where(x => x.Publish).Select(x => x.Culture).ToArray(); + //proceed to publish if all validation still succeeds - var publishStatus = Services.ContentService.SavePublishing(contentItem.PersistedContent, Security.CurrentUser.Id); + var publishStatus = Services.ContentService.SaveAndPublish(contentItem.PersistedContent, culturesToPublish, Security.CurrentUser.Id); wasCancelled = publishStatus.Result == PublishResultType.FailedPublishCancelledByEvent; - successfulCultures = contentItem.Variants.Where(x => x.Publish).Select(x => x.Culture).ToArray(); + successfulCultures = culturesToPublish; return publishStatus; } else @@ -1219,6 +1220,10 @@ namespace Umbraco.Web.Editors /// /// /// + /// + /// + /// + /// /// private bool ValidatePublishingMandatoryLanguages( ContentItemSave contentItem, @@ -1240,7 +1245,7 @@ namespace Umbraco.Web.Editors var isPublished = contentItem.PersistedContent.Published && contentItem.PersistedContent.IsCulturePublished(culture); result.Add((mandatoryVariant, isPublished)); - var isPublishing = isPublished ? true : publishingCheck(mandatoryVariant); + var isPublishing = isPublished || publishingCheck(mandatoryVariant); if (isPublished || isPublishing) continue; @@ -1254,7 +1259,7 @@ namespace Umbraco.Web.Editors } /// - /// This will call PublishCulture on the content item for each culture that needs to be published including the invariant culture + /// Call PublishCulture on the content item for each culture to get a validation result for each culture /// /// /// @@ -1311,7 +1316,7 @@ namespace Umbraco.Web.Editors return HandleContentNotFound(id, false); } - var publishResult = Services.ContentService.SavePublishing(foundContent, Security.GetUserId().ResultOr(0)); + var publishResult = Services.ContentService.SaveAndPublish(foundContent, userId: Security.GetUserId().ResultOr(0)); if (publishResult.Success == false) { var notificationModel = new SimpleNotificationModel();