diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs
index d18e6b46a9..8ec7cf5e5e 100644
--- a/src/Umbraco.Core/Models/Content.cs
+++ b/src/Umbraco.Core/Models/Content.cs
@@ -257,5 +257,19 @@ namespace Umbraco.Core.Models
ChangePublishedState(false);
}
}
+
+ ///
+ /// Creates a clone of the current entity
+ ///
+ ///
+ public IContent Clone()
+ {
+ var clone = (Content)this.MemberwiseClone();
+ clone.Key = Guid.Empty;
+ clone.Version = Guid.NewGuid();
+ clone.ResetIdentity();
+
+ return clone;
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs
index e806aa956f..94cc87d121 100644
--- a/src/Umbraco.Core/Models/ContentTypeBase.cs
+++ b/src/Umbraco.Core/Models/ContentTypeBase.cs
@@ -45,7 +45,7 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo(x => x.UserId);
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo>(x => x.AllowedContentTypes);
- private readonly static PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups);
+ private static readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo(x => x.PropertyGroups);
protected void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
@@ -57,7 +57,7 @@ namespace Umbraco.Core.Models
///
/// Might not be necessary if handled as a relation?
[DataMember]
- public int ParentId
+ public virtual int ParentId
{
get { return _parentId; }
set
@@ -71,7 +71,7 @@ namespace Umbraco.Core.Models
/// Gets or sets the name of the current entity
///
[DataMember]
- public string Name
+ public virtual string Name
{
get { return _name; }
set
@@ -85,7 +85,7 @@ namespace Umbraco.Core.Models
/// Gets or sets the level of the content entity
///
[DataMember]
- public int Level //NOTE Is this relevant for a ContentType?
+ public virtual int Level //NOTE Is this relevant for a ContentType?
{
get { return _level; }
set
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Models
/// Gets of sets the path
///
[DataMember]
- public string Path //NOTE Is this relevant for a ContentType?
+ public virtual string Path //NOTE Is this relevant for a ContentType?
{
get { return _path; }
set
@@ -113,7 +113,7 @@ namespace Umbraco.Core.Models
/// The Alias of the ContentType
///
[DataMember]
- public string Alias
+ public virtual string Alias
{
get { return _alias; }
set
@@ -127,7 +127,7 @@ namespace Umbraco.Core.Models
/// Description for the ContentType
///
[DataMember]
- public string Description
+ public virtual string Description
{
get { return _description; }
set
@@ -141,7 +141,7 @@ namespace Umbraco.Core.Models
/// Gets or sets the sort order of the content entity
///
[DataMember]
- public int SortOrder
+ public virtual int SortOrder
{
get { return _sortOrder; }
set
@@ -155,7 +155,7 @@ namespace Umbraco.Core.Models
/// Name of the icon (sprite class) used to identify the ContentType
///
[DataMember]
- public string Icon
+ public virtual string Icon
{
get { return _icon; }
set
@@ -169,7 +169,7 @@ namespace Umbraco.Core.Models
/// Name of the thumbnail used to identify the ContentType
///
[DataMember]
- public string Thumbnail
+ public virtual string Thumbnail
{
get { return _thumbnail; }
set
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Models
/// Id of the user who created this Content
///
[DataMember]
- public int UserId
+ public virtual int UserId
{
get { return _userId; }
set
@@ -198,7 +198,7 @@ namespace Umbraco.Core.Models
/// If ContentType is Trashed it will be located in the Recyclebin.
///
[DataMember]
- public bool Trashed //NOTE Is this relevant for a ContentType?
+ public virtual bool Trashed //NOTE Is this relevant for a ContentType?
{
get { return _trashed; }
set
@@ -212,7 +212,7 @@ namespace Umbraco.Core.Models
/// Gets or sets a list of integer Ids for allowed ContentTypes
///
[DataMember]
- public IEnumerable AllowedContentTypes
+ public virtual IEnumerable AllowedContentTypes
{
get { return _allowedContentTypes; }
set
@@ -227,7 +227,7 @@ namespace Umbraco.Core.Models
///
/// A PropertyGroup corresponds to a Tab in the UI
[DataMember]
- public PropertyGroupCollection PropertyGroups
+ public virtual PropertyGroupCollection PropertyGroups
{
get { return _propertyGroups; }
set
@@ -242,7 +242,7 @@ namespace Umbraco.Core.Models
/// This list aggregates PropertyTypes across the PropertyGroups.
///
[IgnoreDataMember]
- public IEnumerable PropertyTypes
+ public virtual IEnumerable PropertyTypes
{
get { return PropertyGroups.SelectMany(x => x.PropertyTypes); }
}
diff --git a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
index b09669c2c6..e44bee5dba 100644
--- a/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
+++ b/src/Umbraco.Core/Models/ContentTypeCompositionBase.cs
@@ -5,6 +5,9 @@ using System.Runtime.Serialization;
namespace Umbraco.Core.Models
{
+ ///
+ /// Represents an abstract class for composition specific ContentType properties and methods
+ ///
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
{
private List _contentTypeComposition;
@@ -14,7 +17,7 @@ namespace Umbraco.Core.Models
_contentTypeComposition = new List();
}
- private static readonly PropertyInfo ContentTypeCompositionSelector = ExpressionHelper.GetPropertyInfo>(x => x.ContentTypeComposition);
+ private static readonly PropertyInfo ContentTypeCompositionSelector = ExpressionHelper.GetPropertyInfo>(x => x.ContentTypeComposition);
///
/// List of ContentTypes that make up a composition of PropertyGroups and PropertyTypes for the current ContentType
diff --git a/src/Umbraco.Core/Models/EntityBase/Entity.cs b/src/Umbraco.Core/Models/EntityBase/Entity.cs
index cca3bc501e..109cf08779 100644
--- a/src/Umbraco.Core/Models/EntityBase/Entity.cs
+++ b/src/Umbraco.Core/Models/EntityBase/Entity.cs
@@ -86,6 +86,12 @@ namespace Umbraco.Core.Models.EntityBase
}
}
+ protected void ResetIdentity()
+ {
+ _hasIdentity = false;
+ _id = 0;
+ }
+
///
/// Method to call on entity saved when first added
///
diff --git a/src/Umbraco.Tests/Models/ContentTests.cs b/src/Umbraco.Tests/Models/ContentTests.cs
new file mode 100644
index 0000000000..29069dad97
--- /dev/null
+++ b/src/Umbraco.Tests/Models/ContentTests.cs
@@ -0,0 +1,522 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using Umbraco.Core.Models;
+using Umbraco.Tests.TestHelpers.Entities;
+
+namespace Umbraco.Tests.Models
+{
+ [TestFixture]
+ public class ContentTests
+ {
+ [Test]
+ public void Can_Verify_Mocked_Content()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+
+ // Assert
+ Assert.That(content, Is.Not.Null);
+ }
+
+ [Test]
+ public void Can_Change_Property_Value()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.Properties["title"].Value = "This is the new title";
+
+ // Assert
+ Assert.That(content.Properties.Any(), Is.True);
+ Assert.That(content.Properties["title"], Is.Not.Null);
+ Assert.That(content.Properties["title"].Value, Is.EqualTo("This is the new title"));
+ }
+
+ [Test]
+ public void Can_Clone_Content()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+ content.Id = 10;
+ content.Key = new Guid("29181B97-CB8F-403F-86DE-5FEB497F4800");
+
+ // Act
+ var clone = content.Clone();
+
+ // Assert
+ Assert.AreNotSame(clone, content);
+ Assert.AreNotSame(clone.Id, content.Id);
+ Assert.AreNotSame(clone.Version, content.Version);
+ Assert.That(clone.HasIdentity, Is.False);
+ }
+
+ /*[Test]
+ public void Cannot_Change_Property_With_Invalid_Value()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ var model = new TestEditorModel
+ {
+ TestDateTime = DateTime.UtcNow,
+ TestDouble = 1.2,
+ TestInt = 2,
+ TestReadOnly = "Read-only string",
+ TestString = "This is a test string"
+ };
+
+ // Assert
+ Assert.Throws(() => content.Properties["title"].Value = model);
+ }*/
+
+ [Test]
+ public void Can_Change_Property_Value_Through_Anonymous_Object()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.PropertyValues(new {title = "This is the new title"});
+
+ // Assert
+ Assert.That(content.Properties.Any(), Is.True);
+ Assert.That(content.Properties["title"], Is.Not.Null);
+ Assert.That(content.Properties["title"].Alias, Is.EqualTo("title"));
+ Assert.That(content.Properties["title"].Value, Is.EqualTo("This is the new title"));
+ Assert.That(content.Properties["metaDescription"].Value, Is.EqualTo("The Lorem Ipsum company"));
+ }
+
+ [Test]
+ public void Can_Verify_Dirty_Property_On_Content()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.ResetDirtyProperties();
+ content.Name = "New Home";
+
+ // Assert
+ Assert.That(content.Name, Is.EqualTo("New Home"));
+ Assert.That(content.IsPropertyDirty("Name"), Is.True);
+ }
+
+ [Test]
+ public void Can_Add_PropertyGroup_On_ContentType()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ contentType.PropertyGroups.Add(new PropertyGroup{ Name = "Test Group", SortOrder = 3 });
+
+ // Assert
+ Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(3));
+ Assert.That(content.PropertyGroups.Count(), Is.EqualTo(3));
+ }
+
+ [Test]
+ public void Can_Remove_PropertyGroup_From_ContentType()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ contentType.ResetDirtyProperties();
+
+ // Act
+ contentType.PropertyGroups.Remove("Content");
+
+ // Assert
+ Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(1));
+ Assert.That(contentType.IsPropertyDirty("PropertyGroups"), Is.True);
+ }
+
+ [Test]
+ public void Can_Add_PropertyType_To_Group_On_ContentType()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ contentType.PropertyGroups["Content"].PropertyTypes.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "subtitle",
+ Name = "Subtitle",
+ Description = "Optional subtitle",
+ HelpText = "",
+ Mandatory = false,
+ SortOrder = 3,
+ DataTypeId = -88
+ });
+
+ // Assert
+ Assert.That(contentType.PropertyGroups["Content"].PropertyTypes.Count, Is.EqualTo(3));
+ Assert.That(content.PropertyGroups.First(x => x.Name == "Content").PropertyTypes.Count, Is.EqualTo(3));
+ }
+
+ [Test]
+ public void Can_Add_New_Property_To_New_PropertyType()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ var propertyType = new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "subtitle", Name = "Subtitle", Description = "Optional subtitle", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeId = -88
+ };
+ contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType);
+ content.Properties.Add(new Property(propertyType){Value = "This is a subtitle Test"});
+
+ // Assert
+ Assert.That(content.Properties.Contains("subtitle"), Is.True);
+ Assert.That(content.Properties["subtitle"].Value, Is.EqualTo("This is a subtitle Test"));
+ }
+
+ [Test]
+ public void Can_Add_New_Property_To_New_PropertyType_In_New_PropertyGroup()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ var propertyType = new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "subtitle",
+ Name = "Subtitle",
+ Description = "Optional subtitle",
+ HelpText = "",
+ Mandatory = false,
+ SortOrder = 3,
+ DataTypeId = -88
+ };
+ var propertyGroup = new PropertyGroup {Name = "Test Group", SortOrder = 3};
+ propertyGroup.PropertyTypes.Add(propertyType);
+ contentType.PropertyGroups.Add(propertyGroup);
+ content.Properties.Add(new Property(propertyType){ Value = "Subtitle Test"});
+
+ // Assert
+ Assert.That(content.Properties.Count, Is.EqualTo(5));
+ Assert.That(content.PropertyTypes.Count(), Is.EqualTo(5));
+ Assert.That(content.PropertyGroups.Count(), Is.EqualTo(3));
+ Assert.That(content.Properties["subtitle"].Value, Is.EqualTo("Subtitle Test"));
+ Assert.That(content.Properties["title"].Value, Is.EqualTo("Welcome to our Home page"));
+ }
+
+ [Test]
+ public void Can_Update_PropertyType_Through_Content_Properties()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act - note that the PropertyType's properties like SortOrder is not updated through the Content object
+ var propertyType = new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "title", Name = "Title", Description = "Title description added", HelpText = "", Mandatory = false, SortOrder = 10, DataTypeId = -88
+ };
+ content.Properties.Add(new Property(propertyType));
+
+ // Assert
+ Assert.That(content.Properties.Count, Is.EqualTo(4));
+ Assert.That(contentType.PropertyTypes.First(x => x.Alias == "title").SortOrder, Is.EqualTo(1));
+ Assert.That(content.Properties["title"].Value, Is.EqualTo("Welcome to our Home page"));
+ }
+
+ [Test]
+ public void Can_Change_ContentType_On_Content()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var simpleContentType = MockedContentTypes.CreateSimpleContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.ChangeContentType(simpleContentType);
+
+ // Assert
+ Assert.That(content.Properties.Contains("author"), Is.True);
+ Assert.That(content.PropertyGroups.Count(), Is.EqualTo(1));
+ Assert.That(content.PropertyTypes.Count(), Is.EqualTo(3));
+ //Note: There was 4 properties, after changing ContentType 1 has been added (no properties are deleted)
+ Assert.That(content.Properties.Count, Is.EqualTo(5));
+ }
+
+ [Test]
+ public void Can_Change_ContentType_On_Content_And_Set_Property_Value()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var simpleContentType = MockedContentTypes.CreateSimpleContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.ChangeContentType(simpleContentType);
+ content.SetValue("author", "John Doe");
+
+ // Assert
+ Assert.That(content.Properties.Contains("author"), Is.True);
+ Assert.That(content.Properties["author"].Value, Is.EqualTo("John Doe"));
+ }
+
+ [Test]
+ public void Can_Change_ContentType_On_Content_And_Still_Get_Old_Properties()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var simpleContentType = MockedContentTypes.CreateSimpleContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.ChangeContentType(simpleContentType);
+
+ // Assert
+ Assert.That(content.Properties.Contains("author"), Is.True);
+ Assert.That(content.Properties.Contains("keywords"), Is.True);
+ Assert.That(content.Properties.Contains("metaDescription"), Is.True);
+ Assert.That(content.Properties["keywords"].Value, Is.EqualTo("text,home,page"));
+ Assert.That(content.Properties["metaDescription"].Value, Is.EqualTo("The Lorem Ipsum company"));
+ }
+
+ [Test]
+ 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);
+
+ // 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("metaDescription"), Is.False);
+ }
+
+ [Test]
+ public void Can_Verify_Content_Is_Published()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.ResetDirtyProperties();
+ content.ChangePublishedState(true);
+
+ // Assert
+ Assert.That(content.IsPropertyDirty("Published"), Is.True);
+ Assert.That(content.Published, Is.True);
+ Assert.That(content.IsPropertyDirty("Name"), Is.False);
+ }
+
+ [Test]
+ public void Can_Verify_Content_Is_Trashed()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ var content = MockedContent.CreateTextpageContent(contentType);
+
+ // Act
+ content.ResetDirtyProperties();
+ content.ChangeTrashedState(true);
+
+ // Assert
+ Assert.That(content.IsPropertyDirty("Trashed"), Is.True);
+ Assert.That(content.Trashed, Is.True);
+ Assert.That(content.IsPropertyDirty("Name"), Is.False);
+ }
+
+ [Test]
+ public void Adding_PropertyGroup_To_ContentType_Results_In_Dirty_Entity()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ contentType.ResetDirtyProperties();
+
+ // Act
+ var propertyGroup = new PropertyGroup { Name = "Test Group", SortOrder = 3 };
+ contentType.PropertyGroups.Add(propertyGroup);
+
+ // Assert
+ Assert.That(contentType.IsDirty(), Is.True);
+ Assert.That(contentType.IsPropertyDirty("PropertyGroups"), Is.True);
+ }
+
+ [Test]
+ public void Adding_PropertyType_To_PropertyGroup_On_ContentType_Results_In_Dirty_Entity()
+ {
+ // Arrange
+ var contentType = MockedContentTypes.CreateTextpageContentType();
+ contentType.ResetDirtyProperties();
+
+ // Act
+ var propertyType = new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "subtitle",
+ Name = "Subtitle",
+ Description = "Optional subtitle",
+ HelpText = "",
+ Mandatory = false,
+ SortOrder = 3,
+ DataTypeId = -88
+ };
+ contentType.PropertyGroups["Content"].PropertyTypes.Add(propertyType);
+
+ // Assert
+ Assert.That(contentType.PropertyGroups["Content"].IsDirty(), Is.True);
+ Assert.That(contentType.PropertyGroups["Content"].IsPropertyDirty("PropertyTypes"), Is.True);
+ Assert.That(contentType.PropertyGroups.Any(x => x.IsDirty()), Is.True);
+ }
+
+ [Test]
+ public void Can_Compose_Composite_ContentType_Collection()
+ {
+ // Arrange
+ var simpleContentType = MockedContentTypes.CreateSimpleContentType();
+ var simple2ContentType = MockedContentTypes.CreateSimpleContentType("anotherSimple", "Another Simple Page",
+ new PropertyTypeCollection(
+ new List
+ {
+ new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "coauthor",
+ Name = "Co-Author",
+ Description = "Name of the Co-Author",
+ HelpText = "",
+ Mandatory = false,
+ SortOrder = 4,
+ DataTypeId = -88
+ }
+ }));
+
+ // Act
+ var added = simpleContentType.AddContentType(simple2ContentType);
+ var compositionPropertyGroups = simpleContentType.CompositionPropertyGroups;
+ var compositionPropertyTypes = simpleContentType.CompositionPropertyTypes;
+
+ // Assert
+ Assert.That(added, Is.True);
+ Assert.That(compositionPropertyGroups.Count(), Is.EqualTo(1));
+ Assert.That(compositionPropertyTypes.Count(), Is.EqualTo(4));
+ }
+
+ [Test]
+ public void Can_Compose_Nested_Composite_ContentType_Collection()
+ {
+ // Arrange
+ var metaContentType = MockedContentTypes.CreateMetaContentType();
+ var simpleContentType = MockedContentTypes.CreateSimpleContentType();
+ var simple2ContentType = MockedContentTypes.CreateSimpleContentType("anotherSimple", "Another Simple Page",
+ new PropertyTypeCollection(
+ new List
+ {
+ new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "coauthor",
+ Name = "Co-Author",
+ Description = "Name of the Co-Author",
+ HelpText = "",
+ Mandatory = false,
+ SortOrder = 4,
+ DataTypeId = -88
+ }
+ }));
+
+ // Act
+ var addedMeta = simple2ContentType.AddContentType(metaContentType);
+ var added = simpleContentType.AddContentType(simple2ContentType);
+ var compositionPropertyGroups = simpleContentType.CompositionPropertyGroups;
+ var compositionPropertyTypes = simpleContentType.CompositionPropertyTypes;
+
+ // Assert
+ Assert.That(addedMeta, Is.True);
+ Assert.That(added, Is.True);
+ Assert.That(compositionPropertyGroups.Count(), Is.EqualTo(2));
+ Assert.That(compositionPropertyTypes.Count(), Is.EqualTo(6));
+ Assert.That(simpleContentType.ContentTypeCompositionExists("meta"), Is.True);
+ }
+
+ [Test]
+ public void Can_Avoid_Circular_Dependencies_In_Composition()
+ {
+ var textPage = MockedContentTypes.CreateTextpageContentType();
+ var parent = MockedContentTypes.CreateSimpleContentType("parent", "Parent");
+ var meta = MockedContentTypes.CreateMetaContentType();
+ var mixin1 = MockedContentTypes.CreateSimpleContentType("mixin1", "Mixin1", new PropertyTypeCollection(
+ new List
+ {
+ new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "coauthor",
+ Name = "Co-Author",
+ Description = "Name of the Co-Author",
+ HelpText = "",
+ Mandatory = false,
+ SortOrder = 4,
+ DataTypeId = -88
+ }
+ }));
+ var mixin2 = MockedContentTypes.CreateSimpleContentType("mixin2", "Mixin2", new PropertyTypeCollection(
+ new List
+ {
+ new PropertyType(new Guid(), DataTypeDatabaseType.Ntext)
+ {
+ Alias = "author",
+ Name = "Author",
+ Description = "Name of the Author",
+ HelpText = "",
+ Mandatory = false,
+ SortOrder = 4,
+ DataTypeId = -88
+ }
+ }));
+
+ // Act
+ var addedMetaMixin2 = mixin2.AddContentType(meta);
+ var addedMixin2 = mixin1.AddContentType(mixin2);
+ var addedMeta = parent.AddContentType(meta);
+ var addedMixin1 = parent.AddContentType(mixin1);
+ var addedMixin1Textpage = textPage.AddContentType(mixin1);
+ var addedTextpageParent = parent.AddContentType(textPage);
+
+ var aliases = textPage.CompositionAliases();
+ var propertyTypes = textPage.CompositionPropertyTypes;
+ var propertyGroups = textPage.CompositionPropertyGroups;
+
+ // Assert
+ Assert.That(mixin2.ContentTypeCompositionExists("meta"), Is.True);
+ Assert.That(mixin1.ContentTypeCompositionExists("meta"), Is.True);
+ Assert.That(parent.ContentTypeCompositionExists("meta"), Is.True);
+ Assert.That(textPage.ContentTypeCompositionExists("meta"), Is.True);
+
+ Assert.That(aliases.Count(), Is.EqualTo(3));
+ Assert.That(propertyTypes.Count(), Is.EqualTo(8));
+ Assert.That(propertyGroups.Count(), Is.EqualTo(2));
+
+ Assert.That(addedMeta, Is.True);
+ Assert.That(addedMetaMixin2, Is.True);
+ Assert.That(addedMixin2, Is.True);
+ Assert.That(addedMixin1, Is.False);
+ Assert.That(addedMixin1Textpage, Is.True);
+ Assert.That(addedTextpageParent, Is.False);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs
new file mode 100644
index 0000000000..5c0cce4697
--- /dev/null
+++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs
@@ -0,0 +1,24 @@
+using Umbraco.Core.Models;
+
+namespace Umbraco.Tests.TestHelpers.Entities
+{
+ public class MockedContent
+ {
+ public static Content CreateTextpageContent(ContentType contentType)
+ {
+ var content = new Content(-1, contentType) {Name = "Home", Language = "en-US", Level = 1, ParentId = -1, SortOrder = 1, Template = "~/masterpages/umbTextPage.master", UserId = 0};
+ object obj =
+ new
+ {
+ title = "Welcome to our Home page",
+ bodyText = "This is the welcome message on the first page",
+ keywords = "text,home,page",
+ metaDescription = "The Lorem Ipsum company"
+ };
+
+ content.PropertyValues(obj);
+
+ return content;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs
new file mode 100644
index 0000000000..e36deae013
--- /dev/null
+++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs
@@ -0,0 +1,131 @@
+using System;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Tests.TestHelpers.Entities
+{
+ public class MockedContentTypes
+ {
+ public static ContentType CreateTextpageContentType()
+ {
+ var contentType = new ContentType(-1)
+ {
+ Alias = "textPage",
+ Name = "Text Page",
+ Description = "ContentType used for Text pages",
+ Icon = ".sprTreeDoc3",
+ Thumbnail = "doc.png",
+ SortOrder = 1,
+ UserId = 0,
+ DefaultTemplate = "~/masterpages/umbTextPage.master",
+ Trashed = false
+ };
+
+ var contentCollection = new PropertyTypeCollection();
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 });
+
+ var metaCollection = new PropertyTypeCollection();
+ metaCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "keywords", Name = "Meta Keywords", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
+ metaCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "metaDescription", Name = "Meta Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeId = -89 });
+
+ contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 });
+ contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Meta", SortOrder = 2 });
+
+ return contentType;
+ }
+
+ public static ContentType CreateMetaContentType()
+ {
+ var contentType = new ContentType(-1)
+ {
+ Alias = "meta",
+ Name = "Meta",
+ Description = "ContentType used for Meta tags",
+ Icon = ".sprTreeDoc3",
+ Thumbnail = "doc.png",
+ SortOrder = 1,
+ UserId = 0,
+ DefaultTemplate = "",
+ Trashed = false
+ };
+
+ var metaCollection = new PropertyTypeCollection();
+ metaCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "metakeywords", Name = "Meta Keywords", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
+ metaCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "metadescription", Name = "Meta Description", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeId = -89 });
+
+ contentType.PropertyGroups.Add(new PropertyGroup(metaCollection) { Name = "Meta", SortOrder = 2 });
+
+ return contentType;
+ }
+
+ public static ContentType CreateSimpleContentType()
+ {
+ var contentType = new ContentType(-1)
+ {
+ Alias = "simple",
+ Name = "Simple Page",
+ Description = "ContentType used for simple text pages",
+ Icon = ".sprTreeDoc3",
+ Thumbnail = "doc.png",
+ SortOrder = 1,
+ UserId = 0,
+ DefaultTemplate = "~/masterpages/umbSimplePage.master",
+ Trashed = false
+ };
+
+ var contentCollection = new PropertyTypeCollection();
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 });
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeId = -88 });
+
+ contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 });
+
+ return contentType;
+ }
+
+ public static ContentType CreateSimpleContentType(string alias, string name)
+ {
+ var contentType = new ContentType(-1)
+ {
+ Alias = alias,
+ Name = name,
+ Description = "ContentType used for simple text pages",
+ Icon = ".sprTreeDoc3",
+ Thumbnail = "doc2.png",
+ SortOrder = 1,
+ UserId = 0,
+ DefaultTemplate = "~/masterpages/umbSimplePage.master",
+ Trashed = false
+ };
+
+ var contentCollection = new PropertyTypeCollection();
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeId = -88 });
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeId = -87 });
+ contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeId = -88 });
+
+ contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 });
+
+ return contentType;
+ }
+
+ public static ContentType CreateSimpleContentType(string alias, string name, PropertyTypeCollection collection)
+ {
+ var contentType = new ContentType(-1)
+ {
+ Alias = alias,
+ Name = name,
+ Description = "ContentType used for simple text pages",
+ Icon = ".sprTreeDoc3",
+ Thumbnail = "doc3.png",
+ SortOrder = 1,
+ UserId = 0,
+ DefaultTemplate = "~/masterpages/umbSimplePage.master",
+ Trashed = false
+ };
+
+ contentType.PropertyGroups.Add(new PropertyGroup(collection) { Name = "Content", SortOrder = 1 });
+
+ return contentType;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedEntity.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedEntity.cs
new file mode 100644
index 0000000000..cbe1509327
--- /dev/null
+++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedEntity.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Runtime.Serialization;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Tests.TestHelpers.Entities
+{
+ [Serializable]
+ [DataContract(IsReference = true)]
+ public class MockedEntity : Entity
+ {
+ [DataMember]
+ public string Alias { get; set; }
+
+ [DataMember]
+ public string Name { get; set; }
+
+ [DataMember]
+ public string Value { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index befc241252..0b8cc4e532 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -46,6 +46,7 @@
+
@@ -60,6 +61,7 @@
+
@@ -91,6 +93,9 @@
+
+
+
diff --git a/src/Umbraco.Web/Publishing/IPublishingStrategy.cs b/src/Umbraco.Web/Publishing/IPublishingStrategy.cs
new file mode 100644
index 0000000000..0d61b8602b
--- /dev/null
+++ b/src/Umbraco.Web/Publishing/IPublishingStrategy.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Web.Publishing
+{
+ public interface IPublishingStrategy
+ {
+ bool Publish(IContent content, int userId);
+ bool PublishWithChildren(IEnumerable children, int userId);
+ void PublishWithSubs(IContent content, int userId);
+ bool UnPublish(IContent content, int userId);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Publishing/PublishingStrategy.cs b/src/Umbraco.Web/Publishing/PublishingStrategy.cs
index 17acd13d2b..0f0cb80a7c 100644
--- a/src/Umbraco.Web/Publishing/PublishingStrategy.cs
+++ b/src/Umbraco.Web/Publishing/PublishingStrategy.cs
@@ -1,5 +1,7 @@
-using umbraco.BusinessLogic;
-using umbraco.cms.businesslogic;
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Models;
+using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.web;
namespace Umbraco.Web.Publishing
@@ -7,13 +9,13 @@ namespace Umbraco.Web.Publishing
///
/// Currently acts as an interconnection between the new public api and the legacy api for publishing
///
- internal class PublishingStrategy
+ internal class PublishingStrategy : IPublishingStrategy
{
internal PublishingStrategy()
{
}
-
- internal bool Publish(int userId, int contentId)
+
+ public bool Publish(IContent content, int userId)
{
//Fire BeforePublish event
/*PublishEventArgs e = new PublishEventArgs();
@@ -34,24 +36,33 @@ namespace Umbraco.Web.Publishing
//Updating the cache is not done in the Document-Publish methods, so this part should be added
//global::umbraco.library.UpdateDocumentCache(doc.Id);
+ int contentId = content.Id;
+
var doc = new Document(contentId, true);
var user = new User(userId);
return doc.PublishWithResult(user);
}
- internal bool PublishWithChildren(int userId, int contentId)
+ public bool PublishWithChildren(IEnumerable children, int userId)
{
+ int contentId = children.Last().Id;
var doc = new Document(contentId, true);
var user = new User(userId);
return doc.PublishWithChildrenWithResult(user);
}
- internal void PublishWithSubs(int userId, int contentId)
+ public void PublishWithSubs(IContent content, int userId)
{
+ int contentId = content.Id;
var doc = new Document(contentId, true);
var user = new User(userId);
doc.PublishWithSubs(user);
}
+
+ public bool UnPublish(IContent content, int userId)
+ {
+ return false;
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Services/ContentService.cs b/src/Umbraco.Web/Services/ContentService.cs
index c773d70a53..b6d848907c 100644
--- a/src/Umbraco.Web/Services/ContentService.cs
+++ b/src/Umbraco.Web/Services/ContentService.cs
@@ -3,120 +3,452 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Querying;
+using Umbraco.Core.Persistence.Repositories;
+using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Web.Publishing;
+using Content = Umbraco.Core.Models.Content;
namespace Umbraco.Web.Services
{
public class ContentService : IContentService
{
- public IContent CreateContent(string contentTypeAlias)
+ private readonly IUnitOfWorkProvider _provider;
+ private readonly IPublishingStrategy _publishingStrategy;
+
+ public ContentService() : this(new PetaPocoUnitOfWorkProvider())
{
- throw new NotImplementedException();
}
+ public ContentService(IUnitOfWorkProvider provider) : this(provider, new PublishingStrategy())
+ {
+
+ }
+
+ public ContentService(IUnitOfWorkProvider provider, IPublishingStrategy publishingStrategy)
+ {
+ _provider = provider;
+ _publishingStrategy = publishingStrategy;
+ }
+
+ ///
+ /// Creates an object using the alias of the
+ /// that this Content is based on.
+ ///
+ /// Id of Parent for content
+ /// Alias of the
+ ///
+ public IContent CreateContent(int parentId, string contentTypeAlias)
+ {
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ var query = Query.Builder.Where(x => x.Alias == contentTypeAlias);
+ var contentTypes = repository.GetByQuery(query);
+
+ if (!contentTypes.Any())
+ throw new Exception(string.Format("No ContentType matching the passed in Alias: {0} was found", contentTypeAlias));
+
+ var contentType = contentTypes.First();
+
+ if (contentType == null)
+ throw new Exception(string.Format("No ContentType matching the passed in Alias: {0} was found", contentTypeAlias));
+
+ return new Content(parentId, contentType);
+ }
+
+ ///
+ /// Gets an object by Id
+ ///
+ /// Id of the Content to retrieve
+ ///
public IContent GetById(int id)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ return repository.Get(id);
}
+ ///
+ /// Gets a collection of objects by Level
+ ///
+ /// The level to retrieve Content from
+ /// An Enumerable list of objects
public IEnumerable GetByLevel(int level)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var query = Query.Builder.Where(x => x.Level == level);
+ var contents = repository.GetByQuery(query);
+
+ return contents;
}
+ ///
+ /// Gets a collection of objects by Parent Id
+ ///
+ /// Id of the Parent to retrieve Children from
+ /// An Enumerable list of objects
public IEnumerable GetChildren(int id)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var query = Query.Builder.Where(x => x.ParentId == id);
+ var contents = repository.GetByQuery(query);
+
+ return contents;
}
+ ///
+ /// Gets a collection of an objects versions by Id
+ ///
+ ///
+ /// An Enumerable list of objects
public IEnumerable GetVersions(int id)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ var versions = repository.GetAllVersions(id);
+ return versions;
}
+ ///
+ /// Gets a collection of objects, which reside at the first level / root
+ ///
+ /// An Enumerable list of objects
public IEnumerable GetRootContent()
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var query = Query.Builder.Where(x => x.ParentId == -1);
+ var contents = repository.GetByQuery(query);
+
+ return contents;
}
+ ///
+ /// Gets a collection of objects, which has an expiration date greater then today
+ ///
+ /// An Enumerable list of objects
public IEnumerable GetContentForExpiration()
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var query = Query.Builder.Where(x => x.Published == true && x.ExpireDate != null && x.ExpireDate.Value <= DateTime.Now);
+ var contents = repository.GetByQuery(query);
+
+ return contents;
}
+ ///
+ /// Gets a collection of objects, which has a release date greater then today
+ ///
+ /// An Enumerable list of objects
public IEnumerable GetContentForRelease()
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var query = Query.Builder.Where(x => x.Published == true && x.ReleaseDate != null && x.ReleaseDate.Value <= DateTime.Now);
+ var contents = repository.GetByQuery(query);
+
+ return contents;
}
+ ///
+ /// Gets a collection of an objects, which resides in the Recycle Bin
+ ///
+ /// An Enumerable list of objects
public IEnumerable GetContentInRecycleBin()
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var query = Query.Builder.Where(x => x.ParentId == -20);
+ var contents = repository.GetByQuery(query);
+
+ return contents;
}
- public bool RePublishAll()
+ ///
+ /// Re-Publishes all Content
+ ///
+ /// Id of the User issueing the publishing
+ /// True if publishing succeeded, otherwise False
+ public bool RePublishAll(int userId)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var list = new List();
+
+ var rootContent = GetRootContent();
+ foreach (var content in rootContent)
+ {
+ list.AddRange(GetChildrenDeep(content.Id));
+ }
+
+ foreach (var item in list)
+ {
+ ((Content)item).ChangePublishedState(true);
+ repository.AddOrUpdate(item);
+ }
+
+ unitOfWork.Commit();
+
+ return _publishingStrategy.PublishWithChildren(list, userId);
}
+ ///
+ /// Publishes a single object
+ ///
+ /// The to publish
+ /// Id of the User issueing the publishing
+ /// True if publishing succeeded, otherwise False
public bool Publish(IContent content, int userId)
{
- throw new NotImplementedException();
+ return SaveAndPublish(content, userId);
}
+ ///
+ /// Publishes a object and all its children
+ ///
+ /// The to publish along with its children
+ /// Id of the User issueing the publishing
+ /// True if publishing succeeded, otherwise False
public bool PublishWithChildren(IContent content, int userId)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ var list = GetChildrenDeep(content.Id);
+ list.Add(content);
+
+ foreach (var item in list)
+ {
+ ((Content)item).ChangePublishedState(true);
+ repository.AddOrUpdate(item);
+ }
+
+ unitOfWork.Commit();
+
+ return _publishingStrategy.PublishWithChildren(list, userId);
}
+ ///
+ /// UnPublishes a single object
+ ///
+ /// The to publish
+ /// Id of the User issueing the publishing
+ /// True if unpublishing succeeded, otherwise False
+ public bool UnPublish(IContent content, int userId)
+ {
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ ((Content)content).ChangePublishedState(false);
+ repository.AddOrUpdate(content);
+ unitOfWork.Commit();
+
+ return _publishingStrategy.UnPublish(content, userId);
+ }
+
+ ///
+ /// Gets a flat list of decendents of content from parent id
+ ///
+ ///
+ ///
+ private List GetChildrenDeep(int parentId)
+ {
+ var list = new List();
+ var children = GetChildren(parentId);
+ foreach (var child in children)
+ {
+ list.Add(child);
+ list.AddRange(GetChildrenDeep(child.Id));
+ }
+ return list;
+ }
+
+ ///
+ /// Saves and Publishes a single object
+ ///
+ /// The to save and publish
+ /// Id of the User issueing the publishing
+ /// True if publishing succeeded, otherwise False
public bool SaveAndPublish(IContent content, int userId)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ ((Content)content).ChangePublishedState(true);
+ repository.AddOrUpdate(content);
+ unitOfWork.Commit();
+
+ return _publishingStrategy.Publish(content, userId);
}
+ ///
+ /// Saves a single object
+ ///
+ /// The to save
+ /// Id of the User saving the Content
public void Save(IContent content, int userId)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ repository.AddOrUpdate(content);
+ unitOfWork.Commit();
}
+ ///
+ /// Saves a collection of objects
+ ///
+ /// Collection of to save
+ /// Id of the User saving the Content
public void Save(IEnumerable contents, int userId)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ foreach (var content in contents)
+ {
+ repository.AddOrUpdate(content);
+ }
+ unitOfWork.Commit();
}
+ ///
+ /// Deletes all content of specified type. All children of deleted content is moved to Recycle Bin.
+ ///
+ /// This needs extra care and attention as its potentially a dangerous and extensive operation
+ /// Id of the
public void DeleteContentOfType(int contentTypeId)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ //NOTE What about content that has the contenttype as part of its composition?
+ var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId);
+ var contents = repository.GetByQuery(query);
+
+ foreach (var content in contents)
+ {
+ ((Content)content).ChangeTrashedState(true);
+ repository.AddOrUpdate(content);
+ }
+
+ unitOfWork.Commit();
}
+ ///
+ /// Permanently deletes an object
+ ///
+ /// Please note that this method will completely remove the Content from the database
+ /// The to delete
+ /// Id of the User deleting the Content
public void Delete(IContent content, int userId)
{
- throw new NotImplementedException();
+ //TODO This method should handle/react to errors when there is a constraint issue with the content being deleted
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ repository.Delete(content);
+ unitOfWork.Commit();
}
+ ///
+ /// Deletes an object by moving it to the Recycle Bin
+ ///
+ /// Move an item to the Recycle Bin will result in the item being unpublished
+ /// The to delete
+ /// Id of the User deleting the Content
public void MoveToRecycleBin(IContent content, int userId)
{
- throw new NotImplementedException();
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ ((Content)content).ChangeTrashedState(true);
+ repository.AddOrUpdate(content);
+ unitOfWork.Commit();
}
+ ///
+ /// Moves an object to a new location
+ ///
+ /// The to move
+ /// Id of the Content's new Parent
+ /// Id of the User moving the Content
public void Move(IContent content, int parentId, int userId)
{
- throw new NotImplementedException();
+ content.ParentId = parentId;
+ SaveAndPublish(content, userId);
}
+ ///
+ /// Copies an object by creating a new Content object of the same type and copies all data from the current
+ /// to the new copy which is returned.
+ ///
+ /// The to copy
+ /// Id of the Content's new Parent
+ /// Id of the User copying the Content
+ /// The newly created object
public IContent Copy(IContent content, int parentId, int userId)
{
- throw new NotImplementedException();
+ var copy = ((Content) content).Clone();
+ copy.ParentId = parentId;
+
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+
+ repository.AddOrUpdate(copy);
+ unitOfWork.Commit();
+
+ return copy;
}
- public void SendToPublication(IContent content, int userId)
+ ///
+ /// Sends an to Publication, which executes handlers and events for the 'Send to Publication' action.
+ ///
+ /// The to send to publication
+ /// Id of the User issueing the send to publication
+ /// True if sending publication was succesfull otherwise false
+ public bool SendToPublication(IContent content, int userId)
{
- throw new NotImplementedException();
+ //TODO Implement something similar to this
+ /*SendToPublishEventArgs e = new SendToPublishEventArgs();
+ FireBeforeSendToPublish(e);
+ if (!e.Cancel)
+ {
+ global::umbraco.BusinessLogic.Actions.Action.RunActionHandlers(content, ActionToPublish.Instance);
+
+ FireAfterSendToPublish(e);
+ return true;
+ }
+
+ return false;*/
+ return false;
}
+ ///
+ /// Rollback an object to a previous version.
+ /// This will create a new version, which is a copy of all the old data.
+ ///
+ /// Id of the being rolled back
+ /// Id of the version to rollback to
+ /// Id of the User issueing the rollback of the Content
+ /// The newly created object
public IContent Rollback(int id, Guid versionId, int userId)
{
- throw new NotImplementedException();
+ //TODO Need to test if this actually works
+ var unitOfWork = _provider.GetUnitOfWork();
+ var repository = RepositoryResolver.ResolveByType(unitOfWork);
+ var content = repository.GetByVersion(id, versionId);
+
+ repository.AddOrUpdate(content);
+ unitOfWork.Commit();
+
+ return content;
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Services/IContentService.cs b/src/Umbraco.Web/Services/IContentService.cs
index 07ace24476..c70c35f0fb 100644
--- a/src/Umbraco.Web/Services/IContentService.cs
+++ b/src/Umbraco.Web/Services/IContentService.cs
@@ -13,9 +13,10 @@ namespace Umbraco.Web.Services
/// Creates an object using the alias of the
/// that this Content is based on.
///
+ /// Id of Parent for content
/// Alias of the
///
- IContent CreateContent(string contentTypeAlias);
+ IContent CreateContent(int parentId, string contentTypeAlias);
//TODO Add CreateNewVersion method? Its currently used in the Document API when Publishing - latest version is published,
//but then a new version is created so latest version is not published.
@@ -76,8 +77,9 @@ namespace Umbraco.Web.Services
///
/// Re-Publishes all Content
///
+ /// Id of the User issueing the publishing
/// True if publishing succeeded, otherwise False
- bool RePublishAll();
+ bool RePublishAll(int userId);
///
/// Publishes a single object
@@ -95,6 +97,14 @@ namespace Umbraco.Web.Services
/// True if publishing succeeded, otherwise False
bool PublishWithChildren(IContent content, int userId);
+ ///
+ /// UnPublishes a single object
+ ///
+ /// The to publish
+ /// Id of the User issueing the publishing
+ /// True if unpublishing succeeded, otherwise False
+ bool UnPublish(IContent content, int userId);
+
///
/// Saves and Publishes a single object
///
@@ -163,7 +173,8 @@ namespace Umbraco.Web.Services
///
/// The to send to publication
/// Id of the User issueing the send to publication
- void SendToPublication(IContent content, int userId);
+ /// True if sending publication was succesfull otherwise false
+ bool SendToPublication(IContent content, int userId);
///
/// Rollback an object to a previous version.
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 5ba769e3d7..0c16cbfd94 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -304,6 +304,7 @@
+