diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs index 1ca6ff4b7c..cc65a8dc5f 100644 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ b/src/Umbraco.Core/Models/ContentExtensions.cs @@ -106,6 +106,22 @@ namespace Umbraco.Core.Models } #endregion + internal static bool IsInRecycleBin(this IContent content) + { + return IsInRecycleBin(content, Constants.System.RecycleBinContent); + } + + internal static bool IsInRecycleBin(this IMedia media) + { + return IsInRecycleBin(media, Constants.System.RecycleBinMedia); + } + + internal static bool IsInRecycleBin(this IContentBase content, int recycleBinId) + { + return content.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Contains(recycleBinId.ToInvariantString()); + } + /// /// Checks if the IContentBase has children /// diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs index d2df3c9050..d0f4357293 100644 --- a/src/Umbraco.Tests/Models/ContentTests.cs +++ b/src/Umbraco.Tests/Models/ContentTests.cs @@ -13,6 +13,32 @@ namespace Umbraco.Tests.Models [TestFixture] public class ContentTests { + [TestCase("-1,-20,12,34,56", false)] + [TestCase("-1,-21,12,34,56", true)] + [TestCase("-1,12,34,56", false)] + public void Is_Media_In_Recycle_Bin(string path, bool isInBin) + { + var mediaType = MockedContentTypes.CreateImageMediaType(); + var media = MockedMedia.CreateMediaFile(mediaType, -1); + media.Path = path; + media.Id = 34; + + Assert.AreEqual(isInBin, media.IsInRecycleBin()); + } + + [TestCase("-1,-20,12,34,56", true)] + [TestCase("-1,-21,12,34,56", false)] + [TestCase("-1,12,34,56", false)] + public void Is_Content_In_Recycle_Bin(string path, bool isInBin) + { + var contentType = MockedContentTypes.CreateSimpleContentType(); + var content = MockedContent.CreateSimpleContent(contentType); + content.Path = path; + content.Id = 34; + + Assert.AreEqual(isInBin, content.IsInRecycleBin()); + } + [Test] public void Get_Non_Grouped_Properties() { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js index 43de6f1f46..5e2286536b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js @@ -98,7 +98,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc /** Gets a child node by id */ getChildNode: function(treeNode, id) { var found = _.find(treeNode.children, function (child) { - return child.id === id; + return String(child.id) === String(id); }); return found === undefined ? null : found; }, diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js index b6602e3911..a38efec646 100644 --- a/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js @@ -53,10 +53,21 @@ describe('tree service tests', function () { beforeEach(inject(function ($injector) { treeService = $injector.get('treeService'); - })); + })); describe('query existing node structure of the tree', function () { + it('can get a descendant node with string id', function () { + + var tree = getContentTree(); + var found = treeService.getDescendantNode(tree, "13"); + + expect(found).toBeDefined(); + expect(found).not.toBeNull(); + expect(found.id).toBe(13); + expect(found.name).toBe("random-name-3"); + }); + it('can get a descendant node', function() { var tree = getContentTree(); diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index e781213998..1c1ec80508 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -19,6 +19,7 @@ using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Binders; using Umbraco.Web.WebApi.Filters; using umbraco; +using Umbraco.Core.Models; namespace Umbraco.Web.Editors { @@ -177,7 +178,7 @@ namespace Umbraco.Web.Editors } /// - /// Deletes an item + /// Moves an item to the recycle bin, if it is already there then it will permanently delete it /// /// /// @@ -186,9 +187,19 @@ namespace Umbraco.Web.Editors var foundContent = Services.ContentService.GetById(id); if (foundContent == null) { - HandleContentNotFound(id); + return HandleContentNotFound(id, false); } - Services.ContentService.Delete(foundContent, UmbracoUser.Id); + + //if the current item is in the recycle bin + if (foundContent.IsInRecycleBin() == false) + { + Services.ContentService.MoveToRecycleBin(foundContent, UmbracoUser.Id); + } + else + { + Services.ContentService.Delete(foundContent, UmbracoUser.Id); + } + return Request.CreateResponse(HttpStatusCode.OK); } diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs index 12da55b2ee..bb375ce3b7 100644 --- a/src/Umbraco.Web/Editors/ContentControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs @@ -33,13 +33,17 @@ namespace Umbraco.Web.Editors { } - protected void HandleContentNotFound(int id) + protected HttpResponseMessage HandleContentNotFound(int id, bool throwException = true) { ModelState.AddModelError("id", string.Format("content with id: {0} was not found", id)); var errorResponse = Request.CreateErrorResponse( HttpStatusCode.NotFound, ModelState); - throw new HttpResponseException(errorResponse); + if (throwException) + { + throw new HttpResponseException(errorResponse); + } + return errorResponse; } protected void UpdateName(ContentItemSave contentItem)