diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 5c1df82861..f25f850c27 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -1055,7 +1055,7 @@ namespace Umbraco.Core.Services
}
//Ensure that Path and Level is updated on children
- var children = GetChildren(content.Id);
+ var children = GetChildren(content.Id).ToArray();
if (children.Any())
{
foreach (var child in children)
diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs
index d4ffbd2e06..43cc098b66 100644
--- a/src/Umbraco.Core/Services/MediaService.cs
+++ b/src/Umbraco.Core/Services/MediaService.cs
@@ -480,6 +480,8 @@ namespace Umbraco.Core.Services
/// Id of the User moving the Media
public void Move(IMedia media, int parentId, int userId = 0)
{
+ if (media == null) throw new ArgumentNullException("media");
+
using (new WriteLock(Locker))
{
//This ensures that the correct method is called if this method is used to Move to recycle bin.
@@ -492,17 +494,22 @@ namespace Umbraco.Core.Services
if (Moving.IsRaisedEventCancelled(new MoveEventArgs(media, parentId), this))
return;
- media.ParentId = parentId;
+ media.ParentId = parentId;
+ if (media.Trashed)
+ {
+ media.ChangeTrashedState(false, parentId);
+ }
Save(media, userId);
- //Ensure that Path and Level is updated on children
- var children = GetChildren(media.Id);
+ //Ensure that relevant properties are updated on children
+ var children = GetChildren(media.Id).ToArray();
if (children.Any())
{
var parentPath = media.Path;
var parentLevel = media.Level;
- var updatedDescendents = UpdatePathAndLevelOnChildren(children, parentPath, parentLevel);
- Save(updatedDescendents, userId);
+ var parentTrashed = media.Trashed;
+ var updatedDescendants = UpdatePropertiesOnChildren(children, parentPath, parentLevel, parentTrashed);
+ Save(updatedDescendants, userId);
}
Moved.RaiseEvent(new MoveEventArgs(media, false, parentId), this);
@@ -511,14 +518,16 @@ namespace Umbraco.Core.Services
}
}
- ///
+ ///
/// Deletes an object by moving it to the Recycle Bin
///
/// The to delete
/// Id of the User deleting the Media
public void MoveToRecycleBin(IMedia media, int userId = 0)
{
- if (Trashing.IsRaisedEventCancelled(new MoveEventArgs(media, -21), this))
+ if (media == null) throw new ArgumentNullException("media");
+
+ if (Trashing.IsRaisedEventCancelled(new MoveEventArgs(media, -21), this))
return;
//Find Descendants, which will be moved to the recycle bin along with the parent/grandparent.
@@ -925,25 +934,31 @@ namespace Umbraco.Core.Services
///
/// Updates the Path and Level on a collection of objects
- /// based on the Parent's Path and Level.
+ /// based on the Parent's Path and Level. Also change the trashed state if relevant.
///
/// Collection of objects to update
/// Path of the Parent media
/// Level of the Parent media
+ /// Indicates whether the Parent is trashed or not
/// Collection of updated objects
- private IEnumerable UpdatePathAndLevelOnChildren(IEnumerable children, string parentPath, int parentLevel)
+ private IEnumerable UpdatePropertiesOnChildren(IEnumerable children, string parentPath, int parentLevel, bool parentTrashed)
{
var list = new List();
foreach (var child in children)
{
child.Path = string.Concat(parentPath, ",", child.Id);
child.Level = parentLevel + 1;
+ if (parentTrashed != child.Trashed)
+ {
+ child.ChangeTrashedState(parentTrashed, child.ParentId);
+ }
+
list.Add(child);
- var grandkids = GetChildren(child.Id);
+ var grandkids = GetChildren(child.Id).ToArray();
if (grandkids.Any())
{
- list.AddRange(UpdatePathAndLevelOnChildren(grandkids, child.Path, child.Level));
+ list.AddRange(UpdatePropertiesOnChildren(grandkids, child.Path, child.Level, child.Trashed));
}
}
return list;
diff --git a/src/Umbraco.Tests/Services/BaseServiceTest.cs b/src/Umbraco.Tests/Services/BaseServiceTest.cs
index cd4318b5a6..b711f7c3ac 100644
--- a/src/Umbraco.Tests/Services/BaseServiceTest.cs
+++ b/src/Umbraco.Tests/Services/BaseServiceTest.cs
@@ -51,6 +51,7 @@ namespace Umbraco.Tests.Services
Content trashed = MockedContent.CreateSimpleContent(contentType, "Text Page Deleted", -20);
trashed.Trashed = true;
ServiceContext.ContentService.Save(trashed, 0);
+
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Services/MediaServiceTests.cs b/src/Umbraco.Tests/Services/MediaServiceTests.cs
new file mode 100644
index 0000000000..fa9e530f3a
--- /dev/null
+++ b/src/Umbraco.Tests/Services/MediaServiceTests.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+using Umbraco.Core.Models;
+using Umbraco.Tests.TestHelpers.Entities;
+
+namespace Umbraco.Tests.Services
+{
+ [TestFixture, RequiresSTA]
+ public class MediaServiceTests : BaseServiceTest
+ {
+ [SetUp]
+ public override void Initialize()
+ {
+ base.Initialize();
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ base.TearDown();
+ }
+
+ [Test]
+ public void Can_Move_Media()
+ {
+ // Arrange
+ var mediaItems = CreateTrashedTestMedia();
+ var mediaService = ServiceContext.MediaService;
+ var media = mediaService.GetById(mediaItems.Item3.Id);
+
+ // Act
+ mediaService.Move(media, mediaItems.Item2.Id);
+
+ // Assert
+ Assert.That(media.ParentId, Is.EqualTo(mediaItems.Item2.Id));
+ Assert.That(media.Trashed, Is.False);
+ }
+
+ [Test]
+ public void Can_Move_Media_To_RecycleBin()
+ {
+ // Arrange
+ var mediaItems = CreateTrashedTestMedia();
+ var mediaService = ServiceContext.MediaService;
+ var media = mediaService.GetById(mediaItems.Item1.Id);
+
+ // Act
+ mediaService.MoveToRecycleBin(media);
+
+ // Assert
+ Assert.That(media.ParentId, Is.EqualTo(-21));
+ Assert.That(media.Trashed, Is.True);
+ }
+
+ [Test]
+ public void Can_Move_Media_From_RecycleBin()
+ {
+ // Arrange
+ var mediaItems = CreateTrashedTestMedia();
+ var mediaService = ServiceContext.MediaService;
+ var media = mediaService.GetById(mediaItems.Item4.Id);
+
+ // Act - moving out of recycle bin
+ mediaService.Move(media, mediaItems.Item1.Id);
+ var mediaChild = mediaService.GetById(mediaItems.Item5.Id);
+
+ // Assert
+ Assert.That(media.ParentId, Is.EqualTo(mediaItems.Item1.Id));
+ Assert.That(media.Trashed, Is.False);
+ Assert.That(mediaChild.ParentId, Is.EqualTo(mediaItems.Item4.Id));
+ Assert.That(mediaChild.Trashed, Is.False);
+ }
+
+ private Tuple CreateTrashedTestMedia()
+ {
+ //Create and Save folder-Media -> 1050
+ var folderMediaType = ServiceContext.ContentTypeService.GetMediaType(1031);
+ var folder = MockedMedia.CreateMediaFolder(folderMediaType, -1);
+ ServiceContext.MediaService.Save(folder);
+
+ //Create and Save folder-Media -> 1051
+ var folder2 = MockedMedia.CreateMediaFolder(folderMediaType, -1);
+ ServiceContext.MediaService.Save(folder2);
+
+ //Create and Save image-Media -> 1052
+ var imageMediaType = ServiceContext.ContentTypeService.GetMediaType(1032);
+ var image = (Media)MockedMedia.CreateMediaImage(imageMediaType, 1050);
+ ServiceContext.MediaService.Save(image);
+
+ //Create and Save folder-Media that is trashed -> 1053
+ var folderTrashed = (Media)MockedMedia.CreateMediaFolder(folderMediaType, -21);
+ folderTrashed.Trashed = true;
+ ServiceContext.MediaService.Save(folderTrashed);
+
+ //Create and Save image-Media child of folderTrashed -> 1054
+ var imageTrashed = (Media)MockedMedia.CreateMediaImage(imageMediaType, folderTrashed.Id);
+ imageTrashed.Trashed = true;
+ ServiceContext.MediaService.Save(imageTrashed);
+
+
+ return new Tuple(folder, folder2, image, folderTrashed, imageTrashed);
+ }
+ }
+}
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 5b4b0b41ae..245dc1a050 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -281,6 +281,7 @@
+
diff --git a/src/umbraco.cms/businesslogic/Property/Property.cs b/src/umbraco.cms/businesslogic/Property/Property.cs
index 8adac0d7e3..c11050fae7 100644
--- a/src/umbraco.cms/businesslogic/Property/Property.cs
+++ b/src/umbraco.cms/businesslogic/Property/Property.cs
@@ -39,6 +39,8 @@ namespace umbraco.cms.businesslogic.property
_pt = pt;
_id = Id;
+ if (_pt.DataTypeDefinition.DataType == null)
+ throw new Exception(string.Format("Could not load datatype '{0}'", _pt.DataTypeDefinition.Text));
_data = _pt.DataTypeDefinition.DataType.Data;
_data.PropertyId = Id;
}
@@ -49,6 +51,8 @@ namespace umbraco.cms.businesslogic.property
_pt = PropertyType.GetPropertyType(
SqlHelper.ExecuteScalar("select propertytypeid from cmsPropertyData where id = @id",
SqlHelper.CreateParameter("@id", Id)));
+ if (_pt.DataTypeDefinition.DataType == null)
+ throw new Exception(string.Format("Could not load datatype '{0}'", _pt.DataTypeDefinition.Text));
_data = _pt.DataTypeDefinition.DataType.Data;
_data.PropertyId = Id;
}
@@ -61,6 +65,8 @@ namespace umbraco.cms.businesslogic.property
//Just to ensure that there is a PropertyType available
_pt = PropertyType.GetPropertyType(property.PropertyTypeId);
+ if (_pt.DataTypeDefinition.DataType == null)
+ throw new Exception(string.Format("Could not load datatype '{0}'", _pt.DataTypeDefinition.Text));
_data = _pt.DataTypeDefinition.DataType.Data;
_data.PropertyId = Id;
@@ -152,4 +158,4 @@ namespace umbraco.cms.businesslogic.property
}
}
-}
\ No newline at end of file
+}