diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 76a817b63c..40b350cf15 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -2006,6 +2006,96 @@ namespace Umbraco.Core.Services } } + return true; + } + + /// + /// Sorts a collection of objects by updating the SortOrder according + /// to the ordering of node Ids passed in. + /// + /// + /// Using this method will ensure that the Published-state is maintained upon sorting + /// so the cache is updated accordingly - as needed. + /// + /// + /// + /// + /// True if sorting succeeded, otherwise False + public bool Sort(int[] ids, int userId = 0, bool raiseEvents = true) + { + var shouldBePublished = new List(); + var shouldBeSaved = new List(); + + using (new WriteLock(Locker)) + { + var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x); + var items = ids.Select(x => allContent[x]); + + using (var uow = UowProvider.GetUnitOfWork()) + { + var asArray = items.ToArray(); + var saveEventArgs = new SaveEventArgs(asArray); + if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs)) + { + uow.Commit(); + return false; + } + + var repository = RepositoryFactory.CreateContentRepository(uow); + + var i = 0; + foreach (var content in asArray) + { + //If the current sort order equals that of the content + //we don't need to update it, so just increment the sort order + //and continue. + if (content.SortOrder == i) + { + i++; + continue; + } + + content.SortOrder = i; + content.WriterId = userId; + i++; + + if (content.Published) + { + //TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable! + var published = _publishingStrategy.Publish(uow, content, userId).Success; + shouldBePublished.Add(content); + } + else + shouldBeSaved.Add(content); + + repository.AddOrUpdate(content); + //add or update a preview + repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); + } + + foreach (var content in shouldBePublished) + { + //Create and Save ContentXml DTO + repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); + } + + if (raiseEvents) + { + saveEventArgs.CanCancel = false; + uow.Events.Dispatch(Saved, this, saveEventArgs); + } + + if (shouldBePublished.Any()) + { + //TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable! + _publishingStrategy.PublishingFinalized(uow, shouldBePublished, false); + } + + Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0); + uow.Commit(); + } + } + return true; } diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index 7a5c64c0c0..14ef94bd7a 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -642,7 +642,21 @@ namespace Umbraco.Core.Services /// /// /// True if sorting succeeded, otherwise False - bool Sort(IEnumerable items, int userId = 0, bool raiseEvents = true); + bool Sort(IEnumerable items, int userId = 0, bool raiseEvents = true); + + /// + /// Sorts a collection of objects by updating the SortOrder according + /// to the ordering of node Ids passed in. + /// + /// + /// Using this method will ensure that the Published-state is maintained upon sorting + /// so the cache is updated accordingly - as needed. + /// + /// + /// + /// + /// True if sorting succeeded, otherwise False + bool Sort(int[] ids, int userId = 0, bool raiseEvents = true); /// /// Gets the parent of the current content as an item. diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index d53ee84e7c..6b3a73f5df 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -792,11 +792,8 @@ namespace Umbraco.Web.Editors { var contentService = Services.ContentService; - // content service GetByIds does order the content items based on the order of Ids passed in - var content = contentService.GetByIds(sorted.IdSortOrder); - // Save content with new sort order and update content xml in db accordingly - if (contentService.Sort(content) == false) + if (contentService.Sort(sorted.IdSortOrder) == false) { LogHelper.Warn("Content sorting failed, this was probably caused by an event being cancelled"); return Request.CreateValidationErrorResponse("Content sorting failed, this was probably caused by an event being cancelled"); diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs index 505d715c3e..e7603abe2e 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs @@ -175,13 +175,16 @@ namespace umbraco.presentation.webservices { var contentService = ApplicationContext.Services.ContentService; try - { - var intIds = ids.Select(int.Parse).ToArray(); - var allContent = contentService.GetByIds(intIds).ToDictionary(x => x.Id, x => x); - var sortedContent = intIds.Select(x => allContent[x]); - + { // Save content with new sort order and update db+cache accordingly - var sorted = contentService.Sort(sortedContent); + var intIds = new List(); + foreach (var stringId in ids) + { + int intId; + if (int.TryParse(stringId, out intId)) + intIds.Add(intId); + } + var sorted = contentService.Sort(intIds.ToArray()); // refresh sort order on cached xml // but no... this is not distributed - solely relying on content service & events should be enough