From b270cefacc0857c1701d01248887e33fd9365526 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 17 Dec 2013 14:53:21 +1100 Subject: [PATCH 1/2] Upgrading member repositories and services with tests --- src/Umbraco.Core/Models/ContentExtensions.cs | 17 +- .../Services/ContentTypeService.cs | 46 +- .../Services/ContentTypeServiceBase.cs | 65 +++ src/Umbraco.Core/Services/IMemberService.cs | 5 +- .../Services/IMemberTypeService.cs | 30 ++ src/Umbraco.Core/Services/MediaService.cs | 2 +- src/Umbraco.Core/Services/MemberService.cs | 126 +++++- .../Services/MemberTypeService.cs | 157 ++++++- src/Umbraco.Core/Services/ServiceContext.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Repositories/MemberTypeRepositoryTest.cs | 27 ++ .../Services/MemberTypeServiceTests.cs | 417 ++++++++++++++++++ .../Entities/MockedContentTypes.cs | 6 +- .../TestHelpers/Entities/MockedMember.cs | 21 + src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 15 files changed, 864 insertions(+), 59 deletions(-) create mode 100644 src/Umbraco.Core/Services/ContentTypeServiceBase.cs create mode 100644 src/Umbraco.Tests/Services/MemberTypeServiceTests.cs diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs index 04a7ccb27b..8b3440d435 100644 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ b/src/Umbraco.Core/Models/ContentExtensions.cs @@ -613,11 +613,16 @@ namespace Umbraco.Core.Models return ApplicationContext.Current.Services.PackagingService.Export(media); } + /// + /// Creates the full xml representation for the object and all of it's descendants + /// + /// to generate xml for + /// Xml representation of the passed in internal static XElement ToDeepXml(this IMedia media) { return ApplicationContext.Current.Services.PackagingService.Export(media, true); } - + /// /// Creates the xml representation for the object /// @@ -630,5 +635,15 @@ namespace Umbraco.Core.Models //If current IContent is published we should get latest unpublished version return content.ToXml(); } + + /// + /// Creates the xml representation for the object + /// + /// to generate xml for + /// Xml representation of the passed in + public static XElement ToXml(this IMember member) + { + return ApplicationContext.Current.Services.PackagingService.Export(member); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index 9d0a8265b6..e9b6c02e77 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -10,7 +10,6 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; @@ -21,7 +20,7 @@ namespace Umbraco.Core.Services /// /// Represents the ContentType Service, which is an easy access to operations involving /// - public class ContentTypeService : IContentTypeService + public class ContentTypeService : ContentTypeServiceBase, IContentTypeService { private readonly RepositoryFactory _repositoryFactory; private readonly IContentService _contentService; @@ -147,48 +146,7 @@ namespace Umbraco.Core.Services private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes) { - var toUpdate = new List(); - - foreach (var contentType in contentTypes) - { - //we need to determine if we need to refresh the xml content in the database. This is to be done when: - // - the item is not new (already existed in the db) AND - // - a content type changes it's alias OR - // - if a content type has it's property removed OR - // - if a content type has a property whose alias has changed - //here we need to check if the alias of the content type changed or if one of the properties was removed. - var dirty = contentType as IRememberBeingDirty; - if (dirty == null) continue; - - //check if any property types have changed their aliases (and not new property types) - var hasAnyPropertiesChangedAlias = contentType.PropertyTypes.Any(propType => - { - var dirtyProperty = propType as IRememberBeingDirty; - if (dirtyProperty == null) return false; - return dirtyProperty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new' - && dirtyProperty.WasPropertyDirty("Alias"); //alias has changed - }); - - if (dirty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new' - && (dirty.WasPropertyDirty("Alias") || dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") || hasAnyPropertiesChangedAlias)) - { - //If the alias was changed then we only need to update the xml structures for content of the current content type. - //If a property was deleted or a property alias was changed then we need to update the xml structures for any - // content of the current content type and any of the content type's child content types. - if (dirty.WasPropertyDirty("Alias") - && dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") == false && hasAnyPropertiesChangedAlias == false) - { - //if only the alias changed then only update the current content type - toUpdate.Add(contentType); - } - else - { - //if a property was deleted or alias changed, then update all content of the current content type - // and all of it's desscendant doc types. - toUpdate.AddRange(contentType.DescendantsAndSelf()); - } - } - } + var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray(); if (toUpdate.Any()) { diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs new file mode 100644 index 0000000000..b5115d61c2 --- /dev/null +++ b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs @@ -0,0 +1,65 @@ +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; + +namespace Umbraco.Core.Services +{ + public class ContentTypeServiceBase + { + /// + /// This is called after an content type is saved and is used to update the content xml structures in the database + /// if they are required to be updated. + /// + /// + internal IEnumerable GetContentTypesForXmlUpdates(params IContentTypeBase[] contentTypes) + { + + var toUpdate = new List(); + + foreach (var contentType in contentTypes) + { + //we need to determine if we need to refresh the xml content in the database. This is to be done when: + // - the item is not new (already existed in the db) AND + // - a content type changes it's alias OR + // - if a content type has it's property removed OR + // - if a content type has a property whose alias has changed + //here we need to check if the alias of the content type changed or if one of the properties was removed. + var dirty = contentType as IRememberBeingDirty; + if (dirty == null) continue; + + //check if any property types have changed their aliases (and not new property types) + var hasAnyPropertiesChangedAlias = contentType.PropertyTypes.Any(propType => + { + var dirtyProperty = propType as IRememberBeingDirty; + if (dirtyProperty == null) return false; + return dirtyProperty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new' + && dirtyProperty.WasPropertyDirty("Alias"); //alias has changed + }); + + if (dirty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new' + && (dirty.WasPropertyDirty("Alias") || dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") || hasAnyPropertiesChangedAlias)) + { + //If the alias was changed then we only need to update the xml structures for content of the current content type. + //If a property was deleted or a property alias was changed then we need to update the xml structures for any + // content of the current content type and any of the content type's child content types. + if (dirty.WasPropertyDirty("Alias") + && dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") == false && hasAnyPropertiesChangedAlias == false) + { + //if only the alias changed then only update the current content type + toUpdate.Add(contentType); + } + else + { + //if a property was deleted or alias changed, then update all content of the current content type + // and all of it's desscendant doc types. + toUpdate.AddRange(contentType.DescendantsAndSelf()); + } + } + } + + return toUpdate; + + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs index feefb659fc..703e68be71 100644 --- a/src/Umbraco.Core/Services/IMemberService.cs +++ b/src/Umbraco.Core/Services/IMemberService.cs @@ -19,8 +19,11 @@ namespace Umbraco.Core.Services IMember GetById(int id); IMember GetByKey(Guid id); IEnumerable GetMembersByMemberType(string memberTypeAlias); + IEnumerable GetMembersByMemberType(int memberTypeId); IEnumerable GetMembersByGroup(string memberGroupName); IEnumerable GetAllMembers(params int[] ids); + + void DeleteMembersOfType(int memberTypeId); } /// @@ -38,7 +41,7 @@ namespace Umbraco.Core.Services /// bool Exists(string username); - IMember CreateMember(string username, string email, string password, string memberTypeAlias, int userId = 0); + IMember CreateMember(string username, string email, string password, string memberTypeAlias); IMember GetById(object id); diff --git a/src/Umbraco.Core/Services/IMemberTypeService.cs b/src/Umbraco.Core/Services/IMemberTypeService.cs index 7857e1dda0..399c1500ce 100644 --- a/src/Umbraco.Core/Services/IMemberTypeService.cs +++ b/src/Umbraco.Core/Services/IMemberTypeService.cs @@ -25,5 +25,35 @@ namespace Umbraco.Core.Services /// Alias of the to retrieve /// IMemberType GetMemberType(string alias); + + /// + /// Saves a single object + /// + /// to save + /// Optional Id of the User saving the ContentType + void Save(IMemberType memberType, int userId = 0); + + /// + /// Saves a collection of objects + /// + /// Collection of to save + /// Optional Id of the User saving the ContentTypes + void Save(IEnumerable memberTypes, int userId = 0); + + /// + /// Deletes a single object + /// + /// to delete + /// Deleting a will delete all the objects based on this + /// Optional Id of the User deleting the ContentType + void Delete(IMemberType memberType, int userId = 0); + + /// + /// Deletes a collection of objects + /// + /// Collection of to delete + /// Deleting a will delete all the objects based on this + /// Optional Id of the User deleting the ContentTypes + void Delete(IEnumerable memberTypes, int userId = 0); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 0e7d9dafd8..4fe58904a2 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -598,7 +598,7 @@ namespace Umbraco.Core.Services //The ContentType has to be removed from the composition somehow as it would otherwise break //Dbl.check+test that the ContentType's Id is removed from the ContentType2ContentType table var query = Query.Builder.Where(x => x.ContentTypeId == mediaTypeId); - var contents = repository.GetByQuery(query); + var contents = repository.GetByQuery(query).ToArray(); if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(contents), this)) return; diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index 61c0725ba8..328cd8207f 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -1,7 +1,11 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Threading; +using System.Xml.Linq; +using Umbraco.Core.Events; using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Persistence.UnitOfWork; @@ -17,6 +21,8 @@ namespace Umbraco.Core.Services private readonly RepositoryFactory _repositoryFactory; private readonly IDatabaseUnitOfWorkProvider _uowProvider; + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); + public MemberService(RepositoryFactory repositoryFactory) : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory) { @@ -108,6 +114,22 @@ namespace Umbraco.Core.Services } } + /// + /// Gets a list of Members by their MemberType + /// + /// + /// + public IEnumerable GetMembersByMemberType(int memberTypeId) + { + using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork())) + { + repository.Get(memberTypeId); + var query = Query.Builder.Where(x => x.ContentTypeId == memberTypeId); + var members = repository.GetByQuery(query); + return members; + } + } + /// /// Gets a list of Members by the MemberGroup they are part of /// @@ -134,6 +156,29 @@ namespace Umbraco.Core.Services } } + public void DeleteMembersOfType(int memberTypeId) + { + using (new WriteLock(Locker)) + { + using (var uow = _uowProvider.GetUnitOfWork()) + { + var repository = _repositoryFactory.CreateMemberRepository(uow); + //NOTE What about content that has the contenttype as part of its composition? + var query = Query.Builder.Where(x => x.ContentTypeId == memberTypeId); + var members = repository.GetByQuery(query).ToArray(); + + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(members), this)) + return; + + foreach (var member in members) + { + //Permantly delete the member + Delete(member); + } + } + } + } + /// /// Does a search for members that contain the specified string in their email address /// @@ -249,9 +294,8 @@ namespace Umbraco.Core.Services /// /// /// - /// /// - public IMember CreateMember(string email, string username, string password, string memberTypeAlias, int userId = 0) + public IMember CreateMember(string email, string username, string password, string memberTypeAlias) { var uow = _uowProvider.GetUnitOfWork(); IMemberType memberType; @@ -360,5 +404,83 @@ namespace Umbraco.Core.Services } #endregion + + /// + /// Rebuilds all xml content in the cmsContentXml table for all media + /// + /// + /// Only rebuild the xml structures for the content type ids passed in, if none then rebuilds the structures + /// for all members = USE WITH CARE! + /// + /// True if publishing succeeded, otherwise False + internal void RebuildXmlStructures(params int[] memberTypeIds) + { + using (new WriteLock(Locker)) + { + var list = new List(); + + var uow = _uowProvider.GetUnitOfWork(); + + //First we're going to get the data that needs to be inserted before clearing anything, this + //ensures that we don't accidentally leave the content xml table empty if something happens + //during the lookup process. + + if (memberTypeIds.Any() == false) + { + list.AddRange(GetAllMembers()); + } + else + { + list.AddRange(memberTypeIds.SelectMany(GetMembersByMemberType)); + } + + var xmlItems = new List(); + foreach (var c in list) + { + var xml = c.ToXml(); + xmlItems.Add(new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) }); + } + + //Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too. + using (var tr = uow.Database.GetTransaction()) + { + if (memberTypeIds.Any() == false) + { + //Remove all media records from the cmsContentXml table (DO NOT REMOVE Content/Members!) + uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN + (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml + INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id + WHERE nodeObjectType = @nodeObjectType)", + new { nodeObjectType = Constants.ObjectTypes.Member }); + } + else + { + foreach (var id in memberTypeIds) + { + //first we'll clear out the data from the cmsContentXml table for this type + uow.Database.Execute(@"delete from cmsContentXml where nodeId in + (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml + INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id + INNER JOIN cmsContent ON cmsContent.nodeId = umbracoNode.id + WHERE nodeObjectType = @nodeObjectType AND cmsContent.contentType = @contentTypeId)", + new { contentTypeId = id, nodeObjectType = Constants.ObjectTypes.Member }); + } + } + + //bulk insert it into the database + uow.Database.BulkInsertRecords(xmlItems, tr); + } + } + } + + /// + /// Occurs before Delete + /// + public static event TypedEventHandler> Deleting; + + /// + /// Occurs after Delete + /// + public static event TypedEventHandler> Deleted; } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/MemberTypeService.cs b/src/Umbraco.Core/Services/MemberTypeService.cs index 244511c4b3..2c1237c7b1 100644 --- a/src/Umbraco.Core/Services/MemberTypeService.cs +++ b/src/Umbraco.Core/Services/MemberTypeService.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; +using Umbraco.Core.Auditing; +using Umbraco.Core.Events; using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; @@ -8,25 +11,29 @@ using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Services { - internal class MemberTypeService : IMemberTypeService + internal class MemberTypeService : ContentTypeServiceBase, IMemberTypeService { private readonly IDatabaseUnitOfWorkProvider _uowProvider; private readonly RepositoryFactory _repositoryFactory; + private readonly IMemberService _memberService; - public MemberTypeService() - : this(new PetaPocoUnitOfWorkProvider(), new RepositoryFactory()) + private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(); + + public MemberTypeService(IMemberService memberService) + : this(new PetaPocoUnitOfWorkProvider(), new RepositoryFactory(), memberService) { } - public MemberTypeService(RepositoryFactory repositoryFactory) - : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory) + public MemberTypeService(RepositoryFactory repositoryFactory, IMemberService memberService) + : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory, memberService) { } - public MemberTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory) + public MemberTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IMemberService memberService) { if (provider == null) throw new ArgumentNullException("provider"); if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory"); _uowProvider = provider; _repositoryFactory = repositoryFactory; + _memberService = memberService; } public IEnumerable GetAllMemberTypes(params int[] ids) @@ -66,5 +73,143 @@ namespace Umbraco.Core.Services } } + public void Save(IMemberType memberType, int userId = 0) + { + if (SavingMemberType.IsRaisedEventCancelled(new SaveEventArgs(memberType), this)) + return; + + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow)) + { + memberType.CreatorId = userId; + repository.AddOrUpdate(memberType); + + uow.Commit(); + } + + UpdateContentXmlStructure(memberType); + } + SavedMemberType.RaiseEvent(new SaveEventArgs(memberType, false), this); + } + + public void Save(IEnumerable memberTypes, int userId = 0) + { + var asArray = memberTypes.ToArray(); + + if (SavingMemberType.IsRaisedEventCancelled(new SaveEventArgs(asArray), this)) + return; + + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow)) + { + foreach (var memberType in asArray) + { + memberType.CreatorId = userId; + repository.AddOrUpdate(memberType); + } + + //save it all in one go + uow.Commit(); + } + + UpdateContentXmlStructure(asArray.Cast().ToArray()); + } + SavedMemberType.RaiseEvent(new SaveEventArgs(asArray, false), this); + } + + public void Delete(IMemberType memberType, int userId = 0) + { + if (DeletingMemberType.IsRaisedEventCancelled(new DeleteEventArgs(memberType), this)) + return; + + using (new WriteLock(Locker)) + { + _memberService.DeleteMembersOfType(memberType.Id); + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow)) + { + repository.Delete(memberType); + uow.Commit(); + + DeletedMemberType.RaiseEvent(new DeleteEventArgs(memberType, false), this); + } + } + } + + public void Delete(IEnumerable memberTypes, int userId = 0) + { + var asArray = memberTypes.ToArray(); + + if (DeletingMemberType.IsRaisedEventCancelled(new DeleteEventArgs(asArray), this)) + return; + + using (new WriteLock(Locker)) + { + foreach (var contentType in asArray) + { + _memberService.DeleteMembersOfType(contentType.Id); + } + + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow)) + { + foreach (var memberType in asArray) + { + repository.Delete(memberType); + } + + uow.Commit(); + + DeletedMemberType.RaiseEvent(new DeleteEventArgs(asArray, false), this); + } + } + } + + /// + /// This is called after an IContentType is saved and is used to update the content xml structures in the database + /// if they are required to be updated. + /// + /// A tuple of a content type and a boolean indicating if it is new (HasIdentity was false before committing) + private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes) + { + + var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray(); + + if (toUpdate.Any()) + { + //if it is a media type then call the rebuilding methods for media + var typedMemberService = _memberService as MemberService; + if (typedMemberService != null) + { + typedMemberService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray()); + } + } + + } + + /// + /// Occurs before Save + /// + public static event TypedEventHandler> SavingMemberType; + + /// + /// Occurs after Save + /// + public static event TypedEventHandler> SavedMemberType; + + /// + /// Occurs before Delete + /// + public static event TypedEventHandler> DeletingMemberType; + + /// + /// Occurs after Delete + /// + public static event TypedEventHandler> DeletedMemberType; } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index 28fbd9fffb..ffce7b42ba 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -144,7 +144,7 @@ namespace Umbraco.Core.Services // _macroService = new Lazy(() => new MacroService(provider, repositoryFactory.Value)); if (_memberTypeService == null) - _memberTypeService = new Lazy(() => new MemberTypeService(provider, repositoryFactory.Value)); + _memberTypeService = new Lazy(() => new MemberTypeService(provider, repositoryFactory.Value, _memberService.Value)); } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 8f1415b3b7..0ce3f0bf9a 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -745,6 +745,7 @@ + diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs index 44cc3152f4..4b3a5c2785 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs @@ -91,6 +91,33 @@ namespace Umbraco.Tests.Persistence.Repositories } } + //NOTE: This tests for left join logic (rev 7b14e8eacc65f82d4f184ef46c23340c09569052) + [Test] + public void Can_Get_All_Members_When_No_Properties_Assigned() + { + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + var memberType1 = MockedContentTypes.CreateSimpleMemberType(); + memberType1.PropertyTypeCollection.Clear(); + repository.AddOrUpdate(memberType1); + unitOfWork.Commit(); + + var memberType2 = MockedContentTypes.CreateSimpleMemberType(); + memberType2.PropertyTypeCollection.Clear(); + memberType2.Name = "AnotherType"; + memberType2.Alias = "anotherType"; + repository.AddOrUpdate(memberType2); + unitOfWork.Commit(); + + var result = repository.GetAll(); + + //there are 3 because of the Member type created for init data + Assert.AreEqual(3, result.Count()); + } + } + [Test] public void Can_Get_Member_Type_By_Id() { diff --git a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs new file mode 100644 index 0000000000..eccd845ca2 --- /dev/null +++ b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs @@ -0,0 +1,417 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Tests.TestHelpers.Entities; + +namespace Umbraco.Tests.Services +{ + [TestFixture, RequiresSTA] + public class MemberTypeServiceTests : BaseServiceTest + { + [SetUp] + public override void Initialize() + { + base.Initialize(); + } + + [TearDown] + public override void TearDown() + { + base.TearDown(); + } + + [Test] + public void Deleting_PropertyType_Removes_The_Property_From_Member() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + var initProps = member.Properties.Count; + var initPropTypes = member.PropertyTypes.Count(); + + //remove a property (NOT ONE OF THE DEFAULTS) + memberType.RemovePropertyType(memberType.PropertyTypes.First(x => Constants.Conventions.Member.StandardPropertyTypeStubs.ContainsKey(x.Alias) == false).Alias); + ServiceContext.MemberTypeService.Save(memberType); + + //re-load it from the db + member = ServiceContext.MemberService.GetById(member.Id); + + Assert.AreEqual(initPropTypes - 1, member.PropertyTypes.Count()); + Assert.AreEqual(initProps - 1, member.Properties.Count); + } + + [Test] + public void Rebuild_Content_Xml_On_Alias_Change() + { + var contentType1 = MockedContentTypes.CreateSimpleMemberType("test1", "Test1"); + var contentType2 = MockedContentTypes.CreateSimpleMemberType("test2", "Test2"); + ServiceContext.MemberTypeService.Save(contentType1); + ServiceContext.MemberTypeService.Save(contentType2); + var contentItems1 = MockedMember.CreateSimpleMember(contentType1, 10).ToArray(); + contentItems1.ForEach(x => ServiceContext.MemberService.Save(x)); + var contentItems2 = MockedMember.CreateSimpleMember(contentType2, 5).ToArray(); + contentItems2.ForEach(x => ServiceContext.MemberService.Save(x)); + //only update the contentType1 alias which will force an xml rebuild for all content of that type + contentType1.Alias = "newAlias"; + ServiceContext.MemberTypeService.Save(contentType1); + + foreach (var c in contentItems1) + { + var xml = DatabaseContext.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); + Assert.IsNotNull(xml); + Assert.IsTrue(xml.Xml.StartsWith("("WHERE nodeId = @Id", new { Id = c.Id }); + Assert.IsNotNull(xml); + Assert.IsTrue(xml.Xml.StartsWith(" ServiceContext.ContentService.SaveAndPublish(x)); + var alias = contentType1.PropertyTypes.First().Alias; + var elementToMatch = "<" + alias + ">"; + foreach (var c in contentItems1) + { + var xml = DatabaseContext.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); + Assert.IsNotNull(xml); + Assert.IsTrue(xml.Xml.Contains(elementToMatch)); //verify that it is there before we remove the property + } + + //remove a property + contentType1.RemovePropertyType(contentType1.PropertyTypes.First().Alias); + ServiceContext.ContentTypeService.Save(contentType1); + + var reQueried = ServiceContext.ContentTypeService.GetContentType(contentType1.Id); + var reContent = ServiceContext.ContentService.GetById(contentItems1.First().Id); + + foreach (var c in contentItems1) + { + var xml = DatabaseContext.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); + Assert.IsNotNull(xml); + Assert.IsFalse(xml.Xml.Contains(elementToMatch)); //verify that it is no longer there + } + } + + [Test] + public void Get_Descendants() + { + // Arrange + var contentTypeService = ServiceContext.ContentTypeService; + var hierarchy = CreateContentTypeHierarchy(); + contentTypeService.Save(hierarchy, 0); //ensure they are saved! + var master = hierarchy.First(); + + //Act + var descendants = master.Descendants(); + + //Assert + Assert.AreEqual(10, descendants.Count()); + } + + [Test] + public void Get_Descendants_And_Self() + { + // Arrange + var contentTypeService = ServiceContext.ContentTypeService; + var hierarchy = CreateContentTypeHierarchy(); + contentTypeService.Save(hierarchy, 0); //ensure they are saved! + var master = hierarchy.First(); + + //Act + var descendants = master.DescendantsAndSelf(); + + //Assert + Assert.AreEqual(11, descendants.Count()); + } + + [Test] + public void Can_Bulk_Save_New_Hierarchy_Content_Types() + { + // Arrange + var contentTypeService = ServiceContext.ContentTypeService; + var hierarchy = CreateContentTypeHierarchy(); + + // Act + contentTypeService.Save(hierarchy, 0); + + Assert.That(hierarchy.Any(), Is.True); + Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False); + //all parent id's should be ok, they are lazy and if they equal zero an exception will be thrown + Assert.DoesNotThrow(() => hierarchy.Any(x => x.ParentId != 0)); + for (var i = 0; i < hierarchy.Count(); i++) + { + if (i == 0) continue; + Assert.AreEqual(hierarchy.ElementAt(i).ParentId, hierarchy.ElementAt(i - 1).Id); + } + } + + [Test] + public void Can_Save_ContentType_Structure_And_Create_Content_Based_On_It() + { + // Arrange + var cs = ServiceContext.ContentService; + var cts = ServiceContext.ContentTypeService; + var dtdYesNo = ServiceContext.DataTypeService.GetDataTypeDefinitionById(-49); + var ctBase = new ContentType(-1) { Name = "Base", Alias = "Base", Icon = "folder.gif", Thumbnail = "folder.png" }; + ctBase.AddPropertyType(new PropertyType(dtdYesNo) + { + Name = "Hide From Navigation", + Alias = Constants.Conventions.Content.NaviHide + } + /*,"Navigation"*/); + cts.Save(ctBase); + + var ctHomePage = new ContentType(ctBase) + { + Name = "Home Page", + Alias = "HomePage", + Icon = "settingDomain.gif", + Thumbnail = "folder.png", + AllowedAsRoot = true + }; + ctHomePage.AddPropertyType(new PropertyType(dtdYesNo) { Name = "Some property", Alias = "someProperty" } + /*,"Navigation"*/); + cts.Save(ctHomePage); + + // Act + var homeDoc = cs.CreateContent("Home Page", -1, "HomePage"); + cs.SaveAndPublish(homeDoc); + + // Assert + Assert.That(ctBase.HasIdentity, Is.True); + Assert.That(ctHomePage.HasIdentity, Is.True); + Assert.That(homeDoc.HasIdentity, Is.True); + Assert.That(homeDoc.ContentTypeId, Is.EqualTo(ctHomePage.Id)); + } + + [Test] + public void Can_Create_And_Save_ContentType_Composition() + { + /* + * Global + * - Components + * - Category + */ + var service = ServiceContext.ContentTypeService; + var global = MockedContentTypes.CreateSimpleContentType("global", "Global"); + service.Save(global); + + var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global); + service.Save(components); + + var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components); + service.Save(component); + + var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global); + service.Save(category); + + var success = category.AddContentType(component); + + Assert.That(success, Is.False); + } + + [Test] + public void Can_Remove_ContentType_Composition_From_ContentType() + { + //Test for U4-2234 + var cts = ServiceContext.ContentTypeService; + //Arrange + var component = CreateComponent(); + cts.Save(component); + var banner = CreateBannerComponent(component); + cts.Save(banner); + var site = CreateSite(); + cts.Save(site); + var homepage = CreateHomepage(site); + cts.Save(homepage); + + //Add banner to homepage + var added = homepage.AddContentType(banner); + cts.Save(homepage); + + //Assert composition + var bannerExists = homepage.ContentTypeCompositionExists(banner.Alias); + var bannerPropertyExists = homepage.CompositionPropertyTypes.Any(x => x.Alias.Equals("bannerName")); + Assert.That(added, Is.True); + Assert.That(bannerExists, Is.True); + Assert.That(bannerPropertyExists, Is.True); + Assert.That(homepage.CompositionPropertyTypes.Count(), Is.EqualTo(6)); + + //Remove banner from homepage + var removed = homepage.RemoveContentType(banner.Alias); + cts.Save(homepage); + + //Assert composition + var bannerStillExists = homepage.ContentTypeCompositionExists(banner.Alias); + var bannerPropertyStillExists = homepage.CompositionPropertyTypes.Any(x => x.Alias.Equals("bannerName")); + Assert.That(removed, Is.True); + Assert.That(bannerStillExists, Is.False); + Assert.That(bannerPropertyStillExists, Is.False); + Assert.That(homepage.CompositionPropertyTypes.Count(), Is.EqualTo(4)); + } + + [Test] + public void Can_Copy_ContentType_By_Performing_Clone() + { + // Arrange + var service = ServiceContext.ContentTypeService; + var metaContentType = MockedContentTypes.CreateMetaContentType(); + service.Save(metaContentType); + + var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType); + service.Save(simpleContentType); + var categoryId = simpleContentType.Id; + + // Act + var sut = simpleContentType.Clone("newcategory"); + service.Save(sut); + + // Assert + Assert.That(sut.HasIdentity, Is.True); + + var contentType = service.GetContentType(sut.Id); + var category = service.GetContentType(categoryId); + + Assert.That(contentType.CompositionAliases().Any(x => x.Equals("meta")), Is.True); + Assert.AreEqual(contentType.ParentId, category.ParentId); + Assert.AreEqual(contentType.Level, category.Level); + Assert.AreEqual(contentType.PropertyTypes.Count(), category.PropertyTypes.Count()); + Assert.AreNotEqual(contentType.Id, category.Id); + Assert.AreNotEqual(contentType.Key, category.Key); + Assert.AreNotEqual(contentType.Path, category.Path); + Assert.AreNotEqual(contentType.SortOrder, category.SortOrder); + Assert.AreNotEqual(contentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, category.PropertyTypes.First(x => x.Alias.Equals("title")).Id); + Assert.AreNotEqual(contentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, category.PropertyGroups.First(x => x.Name.Equals("Content")).Id); + + } + + private ContentType CreateComponent() + { + var component = new ContentType(-1) + { + Alias = "component", + Name = "Component", + Description = "ContentType used for Component grouping", + Icon = ".sprTreeDoc3", + Thumbnail = "doc.png", + SortOrder = 1, + CreatorId = 0, + Trashed = false + }; + + var contentCollection = new PropertyTypeCollection(); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "componentGroup", Name = "Component Group", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); + component.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Component", SortOrder = 1 }); + + return component; + } + + private ContentType CreateBannerComponent(ContentType parent) + { + var banner = new ContentType(parent) + { + Alias = "banner", + Name = "Banner Component", + Description = "ContentType used for Banner Component", + Icon = ".sprTreeDoc3", + Thumbnail = "doc.png", + SortOrder = 1, + CreatorId = 0, + Trashed = false + }; + + var propertyType = new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) + { + Alias = "bannerName", + Name = "Banner Name", + Description = "", + HelpText = "", + Mandatory = false, + SortOrder = 2, + DataTypeDefinitionId = -88 + }; + banner.AddPropertyType(propertyType, "Component"); + return banner; + } + + private ContentType CreateSite() + { + var site = new ContentType(-1) + { + Alias = "site", + Name = "Site", + Description = "ContentType used for Site inheritence", + Icon = ".sprTreeDoc3", + Thumbnail = "doc.png", + SortOrder = 2, + CreatorId = 0, + Trashed = false + }; + + var contentCollection = new PropertyTypeCollection(); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "hostname", Name = "Hostname", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); + site.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Site Settings", SortOrder = 1 }); + + return site; + } + + private ContentType CreateHomepage(ContentType parent) + { + var contentType = new ContentType(parent) + { + Alias = "homepage", + Name = "Homepage", + Description = "ContentType used for the Homepage", + Icon = ".sprTreeDoc3", + Thumbnail = "doc.png", + SortOrder = 1, + CreatorId = 0, + Trashed = false + }; + + var contentCollection = new PropertyTypeCollection(); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -87 }); + contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeDefinitionId = -88 }); + + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + + return contentType; + } + + private IEnumerable CreateContentTypeHierarchy() + { + //create the master type + var masterContentType = MockedContentTypes.CreateSimpleContentType("masterContentType", "MasterContentType"); + masterContentType.Key = new Guid("C00CA18E-5A9D-483B-A371-EECE0D89B4AE"); + ServiceContext.ContentTypeService.Save(masterContentType); + + //add the one we just created + var list = new List { masterContentType }; + + for (var i = 0; i < 10; i++) + { + var contentType = MockedContentTypes.CreateSimpleContentType("childType" + i, "ChildType" + i, + //make the last entry in the list, this one's parent + list.Last()); + + list.Add(contentType); + } + + return list; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index cc22ce913b..58d2179a59 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -266,12 +266,12 @@ namespace Umbraco.Tests.TestHelpers.Entities return mediaType; } - public static MemberType CreateSimpleMemberType() + public static MemberType CreateSimpleMemberType(string alias = null, string name = null) { var contentType = new MemberType(-1) { - Alias = "simple", - Name = "Simple Page", + Alias = alias ?? "simple", + Name = name ?? "Simple Page", Description = "ContentType used for simple text pages", Icon = ".sprTreeDoc3", Thumbnail = "doc.png", diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs index 50f829b326..0aa224d635 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -28,6 +29,26 @@ namespace Umbraco.Tests.TestHelpers.Entities member.ResetDirtyProperties(false); return member; + } + + public static IEnumerable CreateSimpleMember(IMemberType memberType, int amount) + { + var list = new List(); + + for (int i = 0; i < amount; i++) + { + var name = "Member No-" + i; + var member = new Member(name, "test" + i + "@test.com", "test" + i, "test" + i, memberType); + member.SetValue("title", name + " member" + i); + member.SetValue("bodyText", "This is a subpage" + i); + member.SetValue("author", "John Doe" + i); + + member.ResetDirtyProperties(false); + + list.Add(member); + } + + return list; } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 2a8b466173..bfe752f202 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -215,6 +215,7 @@ + From 82b2821e27e1bbed1191f98f5e2c5802b8ce54f1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 17 Dec 2013 15:40:47 +1100 Subject: [PATCH 2/2] Gets the members services ensuring members xml is being handled correctly, fixes issue with the static variable holding the default member type properties (this was then persisted in mem and then reused across all member types). Added more unit tests to verify all. --- src/Umbraco.Core/Constants-Conventions.cs | 213 +++----- .../Factories/MemberTypeReadOnlyFactory.cs | 2 +- .../Relators/PropertyDataRelator.cs | 9 +- .../Repositories/MemberTypeRepository.cs | 2 +- src/Umbraco.Core/Services/MemberService.cs | 12 +- .../Repositories/MemberRepositoryTest.cs | 4 +- .../Repositories/MemberTypeRepositoryTest.cs | 28 +- .../Services/MemberServiceTests.cs | 50 ++ .../Services/MemberTypeServiceTests.cs | 513 ++++++++---------- src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 10 files changed, 410 insertions(+), 424 deletions(-) create mode 100644 src/Umbraco.Tests/Services/MemberServiceTests.cs diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs index 81cec10f94..64f1449399 100644 --- a/src/Umbraco.Core/Constants-Conventions.cs +++ b/src/Umbraco.Core/Constants-Conventions.cs @@ -166,140 +166,85 @@ namespace Umbraco.Core public const string FailedPasswordAttemptsLabel = "Failed Password Attempts"; - internal static Dictionary - StandardPropertyTypeStubs = new Dictionary - { - { - Comments, - new PropertyType( - new Guid( - PropertyEditors - .TextboxMultiple), - DataTypeDatabaseType - .Ntext) - { - Alias = Comments, - Name = - CommentsLabel - } - }, - { - FailedPasswordAttempts, - new PropertyType( - new Guid( - PropertyEditors - .Integer), - DataTypeDatabaseType - .Integer) - { - Alias = - FailedPasswordAttempts, - Name = - FailedPasswordAttemptsLabel - } - }, - { - IsApproved, - new PropertyType( - new Guid( - PropertyEditors - .TrueFalse), - DataTypeDatabaseType - .Integer) - { - Alias = IsApproved, - Name = - IsApprovedLabel - } - }, - { - IsLockedOut, - new PropertyType( - new Guid( - PropertyEditors - .TrueFalse), - DataTypeDatabaseType - .Integer) - { - Alias = - IsLockedOut, - Name = - IsLockedOutLabel - } - }, - { - LastLockoutDate, - new PropertyType( - new Guid( - PropertyEditors.Date), - DataTypeDatabaseType - .Date) - { - Alias = - LastLockoutDate, - Name = - LastLockoutDateLabel - } - }, - { - LastLoginDate, - new PropertyType( - new Guid( - PropertyEditors.Date), - DataTypeDatabaseType - .Date) - { - Alias = - LastLoginDate, - Name = - LastLoginDateLabel - } - }, - { - LastPasswordChangeDate, - new PropertyType( - new Guid( - PropertyEditors.Date), - DataTypeDatabaseType - .Date) - { - Alias = - LastPasswordChangeDate, - Name = - LastPasswordChangeDateLabel - } - }, - { - PasswordAnswer, - new PropertyType( - new Guid( - PropertyEditors - .Textbox), - DataTypeDatabaseType - .Nvarchar) - { - Alias = - PasswordAnswer, - Name = - PasswordAnswerLabel - } - }, - { - PasswordQuestion, - new PropertyType( - new Guid( - PropertyEditors - .Textbox), - DataTypeDatabaseType - .Nvarchar) - { - Alias = - PasswordQuestion, - Name = - PasswordQuestionLabel - } - } - }; + internal static Dictionary GetStandardPropertyTypeStubs() + { + return new Dictionary + { + { + Comments, + new PropertyType(new Guid(PropertyEditors.TextboxMultiple), DataTypeDatabaseType.Ntext) + { + Alias = Comments, + Name = CommentsLabel + } + }, + { + FailedPasswordAttempts, + new PropertyType(new Guid(PropertyEditors.Integer), DataTypeDatabaseType.Integer) + { + Alias = FailedPasswordAttempts, + Name = FailedPasswordAttemptsLabel + } + }, + { + IsApproved, + new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer) + { + Alias = IsApproved, + Name = IsApprovedLabel + } + }, + { + IsLockedOut, + new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer) + { + Alias = IsLockedOut, + Name = IsLockedOutLabel + } + }, + { + LastLockoutDate, + new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date) + { + Alias = LastLockoutDate, + Name = LastLockoutDateLabel + } + }, + { + LastLoginDate, + new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date) + { + Alias = LastLoginDate, + Name = LastLoginDateLabel + } + }, + { + LastPasswordChangeDate, + new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date) + { + Alias = LastPasswordChangeDate, + Name = LastPasswordChangeDateLabel + } + }, + { + PasswordAnswer, + new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType.Nvarchar) + { + Alias = PasswordAnswer, + Name = PasswordAnswerLabel + } + }, + { + PasswordQuestion, + new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType + .Nvarchar) + { + Alias = PasswordQuestion, + Name = PasswordQuestionLabel + } + } + }; + } } /// diff --git a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs index 4884a18d98..aaa2183eb6 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs @@ -36,7 +36,7 @@ namespace Umbraco.Core.Persistence.Factories var propertyTypes = GetPropertyTypes(dto, memberType); //By Convention we add 9 stnd PropertyTypes - This is only here to support loading of types that didn't have these conventions before. - var standardPropertyTypes = Constants.Conventions.Member.StandardPropertyTypeStubs; + var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); foreach (var standardPropertyType in standardPropertyTypes) { if(dto.PropertyTypes.Any(x => x.Alias.Equals(standardPropertyType.Key))) continue; diff --git a/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs b/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs index 4eabe8c669..87a66c3984 100644 --- a/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs +++ b/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using Umbraco.Core.Models.Rdbms; namespace Umbraco.Core.Persistence.Relators @@ -20,8 +21,12 @@ namespace Umbraco.Core.Persistence.Relators // Is this the same MemberReadOnlyDto as the current one we're processing if (Current != null && Current.UniqueId == a.UniqueId) { - // Yes, just add this PropertyDataReadOnlyDto to the current MemberReadOnlyDto's collection - Current.Properties.Add(p); + //This property may already be added so we need to check for that + if (Current.Properties.Any(x => x.Id == p.Id) == false) + { + // Yes, just add this PropertyDataReadOnlyDto to the current MemberReadOnlyDto's collection + Current.Properties.Add(p); + } // Return null to indicate we're not done with this MemberReadOnlyDto yet return null; diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs index 73ba016264..5b48bcb768 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs @@ -168,7 +168,7 @@ namespace Umbraco.Core.Persistence.Repositories ((MemberType)entity).AddingEntity(); //By Convention we add 9 stnd PropertyTypes to an Umbraco MemberType - var standardPropertyTypes = Constants.Conventions.Member.StandardPropertyTypeStubs; + var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); foreach (var standardPropertyType in standardPropertyTypes) { entity.AddPropertyType(standardPropertyType.Value); diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index 328cd8207f..b76caadff2 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -288,7 +288,7 @@ namespace Umbraco.Core.Services #region IMembershipMemberService Implementation /// - /// Creates a new Member + /// Creates and persists a new Member /// /// /// @@ -400,6 +400,9 @@ namespace Umbraco.Core.Services { repository.AddOrUpdate(member); uow.Commit(); + + var xml = member.ToXml(); + CreateAndSaveMemberXml(xml, member.Id, uow.Database); } } @@ -473,6 +476,13 @@ namespace Umbraco.Core.Services } } + private void CreateAndSaveMemberXml(XElement xml, int id, UmbracoDatabase db) + { + var poco = new ContentXmlDto { NodeId = id, Xml = xml.ToString(SaveOptions.None) }; + var exists = db.FirstOrDefault("WHERE nodeId = @Id", new { Id = id }) != null; + int result = exists ? db.Update(poco) : Convert.ToInt32(db.Insert(poco)); + } + /// /// Occurs before Delete /// diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index 044fd97845..86a871df11 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -215,8 +215,8 @@ namespace Umbraco.Tests.Persistence.Repositories var sut = repository.Get(member.Id); Assert.That(sut.ContentType.PropertyGroups.Count(), Is.EqualTo(1)); - Assert.That(sut.ContentType.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.StandardPropertyTypeStubs.Count)); - Assert.That(sut.Properties.Count(), Is.EqualTo(3 + Constants.Conventions.Member.StandardPropertyTypeStubs.Count)); + Assert.That(sut.ContentType.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count)); + Assert.That(sut.Properties.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count)); Assert.That(sut.Properties.Any(x => x.HasIdentity == false || x.Id == 0), Is.False); } } diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs index 4b3a5c2785..52dbbb600f 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs @@ -58,9 +58,11 @@ namespace Umbraco.Tests.Persistence.Repositories var sut = repository.Get(memberType.Id); + var standardProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); + Assert.That(sut, Is.Not.Null); Assert.That(sut.PropertyGroups.Count(), Is.EqualTo(1)); - Assert.That(sut.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.StandardPropertyTypeStubs.Count)); + Assert.That(sut.PropertyTypes.Count(), Is.EqualTo(3 + standardProps.Count)); Assert.That(sut.PropertyGroups.Any(x => x.HasIdentity == false || x.Id == 0), Is.False); Assert.That(sut.PropertyTypes.Any(x => x.HasIdentity == false || x.Id == 0), Is.False); @@ -146,11 +148,33 @@ namespace Umbraco.Tests.Persistence.Repositories memberType = repository.Get(memberType.Id); - Assert.That(memberType.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.StandardPropertyTypeStubs.Count)); + Assert.That(memberType.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count)); Assert.That(memberType.PropertyGroups.Count(), Is.EqualTo(1)); } } + //This is to show that new properties are created for each member type - there was a bug before + // that was reusing the same properties with the same Ids between member types + [Test] + public void Built_In_Member_Type_Properties_Are_Not_Reused_For_Different_Member_Types() + { + var provider = new PetaPocoUnitOfWorkProvider(); + var unitOfWork = provider.GetUnitOfWork(); + using (var repository = CreateRepository(unitOfWork)) + { + IMemberType memberType1 = MockedContentTypes.CreateSimpleMemberType(); + IMemberType memberType2 = MockedContentTypes.CreateSimpleMemberType("test2"); + repository.AddOrUpdate(memberType1); + repository.AddOrUpdate(memberType2); + unitOfWork.Commit(); + + var m1Ids = memberType1.PropertyTypes.Select(x => x.Id).ToArray(); + var m2Ids = memberType2.PropertyTypes.Select(x => x.Id).ToArray(); + + Assert.IsFalse(m1Ids.Any(m2Ids.Contains)); + } + } + [Test] public void Can_Delete_MemberType() { diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs new file mode 100644 index 0000000000..7ddbe972ec --- /dev/null +++ b/src/Umbraco.Tests/Services/MemberServiceTests.cs @@ -0,0 +1,50 @@ +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Tests.TestHelpers.Entities; + +namespace Umbraco.Tests.Services +{ + [TestFixture, RequiresSTA] + public class MemberServiceTests : BaseServiceTest + { + [SetUp] + public override void Initialize() + { + base.Initialize(); + } + + [TearDown] + public override void TearDown() + { + base.TearDown(); + } + + [Test] + public void Can_Delete_member() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + + ServiceContext.MemberService.Delete(member); + var deleted = ServiceContext.MemberService.GetById(member.Id); + + // Assert + Assert.That(deleted, Is.Null); + } + + [Test] + public void ContentXml_Created_When_Saved() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + + var xml = DatabaseContext.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = member.Id }); + Assert.IsNotNull(xml); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs index eccd845ca2..3bbb6b7bf6 100644 --- a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs @@ -35,7 +35,8 @@ namespace Umbraco.Tests.Services var initPropTypes = member.PropertyTypes.Count(); //remove a property (NOT ONE OF THE DEFAULTS) - memberType.RemovePropertyType(memberType.PropertyTypes.First(x => Constants.Conventions.Member.StandardPropertyTypeStubs.ContainsKey(x.Alias) == false).Alias); + var standardProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); + memberType.RemovePropertyType(memberType.PropertyTypes.First(x => standardProps.ContainsKey(x.Alias) == false).Alias); ServiceContext.MemberTypeService.Save(memberType); //re-load it from the db @@ -46,7 +47,7 @@ namespace Umbraco.Tests.Services } [Test] - public void Rebuild_Content_Xml_On_Alias_Change() + public void Rebuild_Member_Xml_On_Alias_Change() { var contentType1 = MockedContentTypes.CreateSimpleMemberType("test1", "Test1"); var contentType2 = MockedContentTypes.CreateSimpleMemberType("test2", "Test2"); @@ -75,14 +76,18 @@ namespace Umbraco.Tests.Services } [Test] - public void Rebuild_Content_Xml_On_Property_Removal() + public void Rebuild_Member_Xml_On_Property_Removal() { - var contentType1 = MockedContentTypes.CreateTextpageContentType("test1", "Test1"); - ServiceContext.ContentTypeService.Save(contentType1); - var contentItems1 = MockedContent.CreateTextpageContent(contentType1, -1, 10).ToArray(); - contentItems1.ForEach(x => ServiceContext.ContentService.SaveAndPublish(x)); - var alias = contentType1.PropertyTypes.First().Alias; + var standardProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); + + var contentType1 = MockedContentTypes.CreateSimpleMemberType("test1", "Test1"); + ServiceContext.MemberTypeService.Save(contentType1); + var contentItems1 = MockedMember.CreateSimpleMember(contentType1, 10).ToArray(); + contentItems1.ForEach(x => ServiceContext.MemberService.Save(x)); + + var alias = contentType1.PropertyTypes.First(x => standardProps.ContainsKey(x.Alias) == false).Alias; var elementToMatch = "<" + alias + ">"; + foreach (var c in contentItems1) { var xml = DatabaseContext.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = c.Id }); @@ -90,9 +95,9 @@ namespace Umbraco.Tests.Services Assert.IsTrue(xml.Xml.Contains(elementToMatch)); //verify that it is there before we remove the property } - //remove a property - contentType1.RemovePropertyType(contentType1.PropertyTypes.First().Alias); - ServiceContext.ContentTypeService.Save(contentType1); + //remove a property (NOT ONE OF THE DEFAULTS) + contentType1.RemovePropertyType(alias); + ServiceContext.MemberTypeService.Save(contentType1); var reQueried = ServiceContext.ContentTypeService.GetContentType(contentType1.Id); var reContent = ServiceContext.ContentService.GetById(contentItems1.First().Id); @@ -105,313 +110,259 @@ namespace Umbraco.Tests.Services } } - [Test] - public void Get_Descendants() - { - // Arrange - var contentTypeService = ServiceContext.ContentTypeService; - var hierarchy = CreateContentTypeHierarchy(); - contentTypeService.Save(hierarchy, 0); //ensure they are saved! - var master = hierarchy.First(); + //[Test] + //public void Can_Save_MemberType_Structure_And_Create_A_Member_Based_On_It() + //{ + // // Arrange + // var cs = ServiceContext.MemberService; + // var cts = ServiceContext.MemberTypeService; + // var dtdYesNo = ServiceContext.DataTypeService.GetDataTypeDefinitionById(-49); + // var ctBase = new MemberType(-1) { Name = "Base", Alias = "Base", Icon = "folder.gif", Thumbnail = "folder.png" }; + // ctBase.AddPropertyType(new PropertyType(dtdYesNo) + // { + // Name = "Hide From Navigation", + // Alias = Constants.Conventions.Content.NaviHide + // } + // /*,"Navigation"*/); + // cts.Save(ctBase); - //Act - var descendants = master.Descendants(); + // var ctHomePage = new MemberType(ctBase) + // { + // Name = "Home Page", + // Alias = "HomePage", + // Icon = "settingDomain.gif", + // Thumbnail = "folder.png", + // AllowedAsRoot = true + // }; + // ctHomePage.AddPropertyType(new PropertyType(dtdYesNo) { Name = "Some property", Alias = "someProperty" } + // /*,"Navigation"*/); + // cts.Save(ctHomePage); - //Assert - Assert.AreEqual(10, descendants.Count()); - } + // // Act + // var homeDoc = cs.CreateMember("Test", "test@test.com", "test", "HomePage"); - [Test] - public void Get_Descendants_And_Self() - { - // Arrange - var contentTypeService = ServiceContext.ContentTypeService; - var hierarchy = CreateContentTypeHierarchy(); - contentTypeService.Save(hierarchy, 0); //ensure they are saved! - var master = hierarchy.First(); + // // Assert + // Assert.That(ctBase.HasIdentity, Is.True); + // Assert.That(ctHomePage.HasIdentity, Is.True); + // Assert.That(homeDoc.HasIdentity, Is.True); + // Assert.That(homeDoc.ContentTypeId, Is.EqualTo(ctHomePage.Id)); + //} - //Act - var descendants = master.DescendantsAndSelf(); + //[Test] + //public void Can_Create_And_Save_MemberType_Composition() + //{ + // /* + // * Global + // * - Components + // * - Category + // */ + // var service = ServiceContext.ContentTypeService; + // var global = MockedContentTypes.CreateSimpleContentType("global", "Global"); + // service.Save(global); - //Assert - Assert.AreEqual(11, descendants.Count()); - } + // var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global); + // service.Save(components); - [Test] - public void Can_Bulk_Save_New_Hierarchy_Content_Types() - { - // Arrange - var contentTypeService = ServiceContext.ContentTypeService; - var hierarchy = CreateContentTypeHierarchy(); + // var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components); + // service.Save(component); - // Act - contentTypeService.Save(hierarchy, 0); + // var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global); + // service.Save(category); - Assert.That(hierarchy.Any(), Is.True); - Assert.That(hierarchy.Any(x => x.HasIdentity == false), Is.False); - //all parent id's should be ok, they are lazy and if they equal zero an exception will be thrown - Assert.DoesNotThrow(() => hierarchy.Any(x => x.ParentId != 0)); - for (var i = 0; i < hierarchy.Count(); i++) - { - if (i == 0) continue; - Assert.AreEqual(hierarchy.ElementAt(i).ParentId, hierarchy.ElementAt(i - 1).Id); - } - } + // var success = category.AddContentType(component); - [Test] - public void Can_Save_ContentType_Structure_And_Create_Content_Based_On_It() - { - // Arrange - var cs = ServiceContext.ContentService; - var cts = ServiceContext.ContentTypeService; - var dtdYesNo = ServiceContext.DataTypeService.GetDataTypeDefinitionById(-49); - var ctBase = new ContentType(-1) { Name = "Base", Alias = "Base", Icon = "folder.gif", Thumbnail = "folder.png" }; - ctBase.AddPropertyType(new PropertyType(dtdYesNo) - { - Name = "Hide From Navigation", - Alias = Constants.Conventions.Content.NaviHide - } - /*,"Navigation"*/); - cts.Save(ctBase); + // Assert.That(success, Is.False); + //} - var ctHomePage = new ContentType(ctBase) - { - Name = "Home Page", - Alias = "HomePage", - Icon = "settingDomain.gif", - Thumbnail = "folder.png", - AllowedAsRoot = true - }; - ctHomePage.AddPropertyType(new PropertyType(dtdYesNo) { Name = "Some property", Alias = "someProperty" } - /*,"Navigation"*/); - cts.Save(ctHomePage); + //[Test] + //public void Can_Remove_ContentType_Composition_From_ContentType() + //{ + // //Test for U4-2234 + // var cts = ServiceContext.ContentTypeService; + // //Arrange + // var component = CreateComponent(); + // cts.Save(component); + // var banner = CreateBannerComponent(component); + // cts.Save(banner); + // var site = CreateSite(); + // cts.Save(site); + // var homepage = CreateHomepage(site); + // cts.Save(homepage); - // Act - var homeDoc = cs.CreateContent("Home Page", -1, "HomePage"); - cs.SaveAndPublish(homeDoc); + // //Add banner to homepage + // var added = homepage.AddContentType(banner); + // cts.Save(homepage); - // Assert - Assert.That(ctBase.HasIdentity, Is.True); - Assert.That(ctHomePage.HasIdentity, Is.True); - Assert.That(homeDoc.HasIdentity, Is.True); - Assert.That(homeDoc.ContentTypeId, Is.EqualTo(ctHomePage.Id)); - } + // //Assert composition + // var bannerExists = homepage.ContentTypeCompositionExists(banner.Alias); + // var bannerPropertyExists = homepage.CompositionPropertyTypes.Any(x => x.Alias.Equals("bannerName")); + // Assert.That(added, Is.True); + // Assert.That(bannerExists, Is.True); + // Assert.That(bannerPropertyExists, Is.True); + // Assert.That(homepage.CompositionPropertyTypes.Count(), Is.EqualTo(6)); - [Test] - public void Can_Create_And_Save_ContentType_Composition() - { - /* - * Global - * - Components - * - Category - */ - var service = ServiceContext.ContentTypeService; - var global = MockedContentTypes.CreateSimpleContentType("global", "Global"); - service.Save(global); + // //Remove banner from homepage + // var removed = homepage.RemoveContentType(banner.Alias); + // cts.Save(homepage); - var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global); - service.Save(components); + // //Assert composition + // var bannerStillExists = homepage.ContentTypeCompositionExists(banner.Alias); + // var bannerPropertyStillExists = homepage.CompositionPropertyTypes.Any(x => x.Alias.Equals("bannerName")); + // Assert.That(removed, Is.True); + // Assert.That(bannerStillExists, Is.False); + // Assert.That(bannerPropertyStillExists, Is.False); + // Assert.That(homepage.CompositionPropertyTypes.Count(), Is.EqualTo(4)); + //} - var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components); - service.Save(component); + //[Test] + //public void Can_Copy_ContentType_By_Performing_Clone() + //{ + // // Arrange + // var service = ServiceContext.ContentTypeService; + // var metaContentType = MockedContentTypes.CreateMetaContentType(); + // service.Save(metaContentType); - var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global); - service.Save(category); + // var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType); + // service.Save(simpleContentType); + // var categoryId = simpleContentType.Id; - var success = category.AddContentType(component); + // // Act + // var sut = simpleContentType.Clone("newcategory"); + // service.Save(sut); - Assert.That(success, Is.False); - } + // // Assert + // Assert.That(sut.HasIdentity, Is.True); - [Test] - public void Can_Remove_ContentType_Composition_From_ContentType() - { - //Test for U4-2234 - var cts = ServiceContext.ContentTypeService; - //Arrange - var component = CreateComponent(); - cts.Save(component); - var banner = CreateBannerComponent(component); - cts.Save(banner); - var site = CreateSite(); - cts.Save(site); - var homepage = CreateHomepage(site); - cts.Save(homepage); + // var contentType = service.GetContentType(sut.Id); + // var category = service.GetContentType(categoryId); - //Add banner to homepage - var added = homepage.AddContentType(banner); - cts.Save(homepage); + // Assert.That(contentType.CompositionAliases().Any(x => x.Equals("meta")), Is.True); + // Assert.AreEqual(contentType.ParentId, category.ParentId); + // Assert.AreEqual(contentType.Level, category.Level); + // Assert.AreEqual(contentType.PropertyTypes.Count(), category.PropertyTypes.Count()); + // Assert.AreNotEqual(contentType.Id, category.Id); + // Assert.AreNotEqual(contentType.Key, category.Key); + // Assert.AreNotEqual(contentType.Path, category.Path); + // Assert.AreNotEqual(contentType.SortOrder, category.SortOrder); + // Assert.AreNotEqual(contentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, category.PropertyTypes.First(x => x.Alias.Equals("title")).Id); + // Assert.AreNotEqual(contentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, category.PropertyGroups.First(x => x.Name.Equals("Content")).Id); - //Assert composition - var bannerExists = homepage.ContentTypeCompositionExists(banner.Alias); - var bannerPropertyExists = homepage.CompositionPropertyTypes.Any(x => x.Alias.Equals("bannerName")); - Assert.That(added, Is.True); - Assert.That(bannerExists, Is.True); - Assert.That(bannerPropertyExists, Is.True); - Assert.That(homepage.CompositionPropertyTypes.Count(), Is.EqualTo(6)); + //} - //Remove banner from homepage - var removed = homepage.RemoveContentType(banner.Alias); - cts.Save(homepage); + //private ContentType CreateComponent() + //{ + // var component = new ContentType(-1) + // { + // Alias = "component", + // Name = "Component", + // Description = "ContentType used for Component grouping", + // Icon = ".sprTreeDoc3", + // Thumbnail = "doc.png", + // SortOrder = 1, + // CreatorId = 0, + // Trashed = false + // }; - //Assert composition - var bannerStillExists = homepage.ContentTypeCompositionExists(banner.Alias); - var bannerPropertyStillExists = homepage.CompositionPropertyTypes.Any(x => x.Alias.Equals("bannerName")); - Assert.That(removed, Is.True); - Assert.That(bannerStillExists, Is.False); - Assert.That(bannerPropertyStillExists, Is.False); - Assert.That(homepage.CompositionPropertyTypes.Count(), Is.EqualTo(4)); - } + // var contentCollection = new PropertyTypeCollection(); + // contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "componentGroup", Name = "Component Group", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); + // component.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Component", SortOrder = 1 }); - [Test] - public void Can_Copy_ContentType_By_Performing_Clone() - { - // Arrange - var service = ServiceContext.ContentTypeService; - var metaContentType = MockedContentTypes.CreateMetaContentType(); - service.Save(metaContentType); + // return component; + //} - var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType); - service.Save(simpleContentType); - var categoryId = simpleContentType.Id; + //private ContentType CreateBannerComponent(ContentType parent) + //{ + // var banner = new ContentType(parent) + // { + // Alias = "banner", + // Name = "Banner Component", + // Description = "ContentType used for Banner Component", + // Icon = ".sprTreeDoc3", + // Thumbnail = "doc.png", + // SortOrder = 1, + // CreatorId = 0, + // Trashed = false + // }; - // Act - var sut = simpleContentType.Clone("newcategory"); - service.Save(sut); + // var propertyType = new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) + // { + // Alias = "bannerName", + // Name = "Banner Name", + // Description = "", + // HelpText = "", + // Mandatory = false, + // SortOrder = 2, + // DataTypeDefinitionId = -88 + // }; + // banner.AddPropertyType(propertyType, "Component"); + // return banner; + //} - // Assert - Assert.That(sut.HasIdentity, Is.True); + //private ContentType CreateSite() + //{ + // var site = new ContentType(-1) + // { + // Alias = "site", + // Name = "Site", + // Description = "ContentType used for Site inheritence", + // Icon = ".sprTreeDoc3", + // Thumbnail = "doc.png", + // SortOrder = 2, + // CreatorId = 0, + // Trashed = false + // }; - var contentType = service.GetContentType(sut.Id); - var category = service.GetContentType(categoryId); + // var contentCollection = new PropertyTypeCollection(); + // contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "hostname", Name = "Hostname", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); + // site.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Site Settings", SortOrder = 1 }); - Assert.That(contentType.CompositionAliases().Any(x => x.Equals("meta")), Is.True); - Assert.AreEqual(contentType.ParentId, category.ParentId); - Assert.AreEqual(contentType.Level, category.Level); - Assert.AreEqual(contentType.PropertyTypes.Count(), category.PropertyTypes.Count()); - Assert.AreNotEqual(contentType.Id, category.Id); - Assert.AreNotEqual(contentType.Key, category.Key); - Assert.AreNotEqual(contentType.Path, category.Path); - Assert.AreNotEqual(contentType.SortOrder, category.SortOrder); - Assert.AreNotEqual(contentType.PropertyTypes.First(x => x.Alias.Equals("title")).Id, category.PropertyTypes.First(x => x.Alias.Equals("title")).Id); - Assert.AreNotEqual(contentType.PropertyGroups.First(x => x.Name.Equals("Content")).Id, category.PropertyGroups.First(x => x.Name.Equals("Content")).Id); + // return site; + //} - } + //private ContentType CreateHomepage(ContentType parent) + //{ + // var contentType = new ContentType(parent) + // { + // Alias = "homepage", + // Name = "Homepage", + // Description = "ContentType used for the Homepage", + // Icon = ".sprTreeDoc3", + // Thumbnail = "doc.png", + // SortOrder = 1, + // CreatorId = 0, + // Trashed = false + // }; - private ContentType CreateComponent() - { - var component = new ContentType(-1) - { - Alias = "component", - Name = "Component", - Description = "ContentType used for Component grouping", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; + // var contentCollection = new PropertyTypeCollection(); + // contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); + // contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -87 }); + // contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeDefinitionId = -88 }); - var contentCollection = new PropertyTypeCollection(); - contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "componentGroup", Name = "Component Group", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); - component.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Component", SortOrder = 1 }); + // contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - return component; - } + // return contentType; + //} - private ContentType CreateBannerComponent(ContentType parent) - { - var banner = new ContentType(parent) - { - Alias = "banner", - Name = "Banner Component", - Description = "ContentType used for Banner Component", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; + //private IEnumerable CreateContentTypeHierarchy() + //{ + // //create the master type + // var masterContentType = MockedContentTypes.CreateSimpleContentType("masterContentType", "MasterContentType"); + // masterContentType.Key = new Guid("C00CA18E-5A9D-483B-A371-EECE0D89B4AE"); + // ServiceContext.ContentTypeService.Save(masterContentType); - var propertyType = new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) - { - Alias = "bannerName", - Name = "Banner Name", - Description = "", - HelpText = "", - Mandatory = false, - SortOrder = 2, - DataTypeDefinitionId = -88 - }; - banner.AddPropertyType(propertyType, "Component"); - return banner; - } + // //add the one we just created + // var list = new List { masterContentType }; - private ContentType CreateSite() - { - var site = new ContentType(-1) - { - Alias = "site", - Name = "Site", - Description = "ContentType used for Site inheritence", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 2, - CreatorId = 0, - Trashed = false - }; + // for (var i = 0; i < 10; i++) + // { + // var contentType = MockedContentTypes.CreateSimpleContentType("childType" + i, "ChildType" + i, + // //make the last entry in the list, this one's parent + // list.Last()); - var contentCollection = new PropertyTypeCollection(); - contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "hostname", Name = "Hostname", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); - site.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Site Settings", SortOrder = 1 }); + // list.Add(contentType); + // } - return site; - } - - private ContentType CreateHomepage(ContentType parent) - { - var contentType = new ContentType(parent) - { - Alias = "homepage", - Name = "Homepage", - Description = "ContentType used for the Homepage", - Icon = ".sprTreeDoc3", - Thumbnail = "doc.png", - SortOrder = 1, - CreatorId = 0, - Trashed = false - }; - - var contentCollection = new PropertyTypeCollection(); - contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "title", Name = "Title", Description = "", HelpText = "", Mandatory = false, SortOrder = 1, DataTypeDefinitionId = -88 }); - contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "bodyText", Name = "Body Text", Description = "", HelpText = "", Mandatory = false, SortOrder = 2, DataTypeDefinitionId = -87 }); - contentCollection.Add(new PropertyType(new Guid(), DataTypeDatabaseType.Ntext) { Alias = "author", Name = "Author", Description = "Name of the author", HelpText = "", Mandatory = false, SortOrder = 3, DataTypeDefinitionId = -88 }); - - contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - - return contentType; - } - - private IEnumerable CreateContentTypeHierarchy() - { - //create the master type - var masterContentType = MockedContentTypes.CreateSimpleContentType("masterContentType", "MasterContentType"); - masterContentType.Key = new Guid("C00CA18E-5A9D-483B-A371-EECE0D89B4AE"); - ServiceContext.ContentTypeService.Save(masterContentType); - - //add the one we just created - var list = new List { masterContentType }; - - for (var i = 0; i < 10; i++) - { - var contentType = MockedContentTypes.CreateSimpleContentType("childType" + i, "ChildType" + i, - //make the last entry in the list, this one's parent - list.Last()); - - list.Add(contentType); - } - - return list; - } + // return list; + //} } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index bfe752f202..c51807a7af 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -215,6 +215,7 @@ +