From a21bee6683e1a9078d570ac9de49c858567ceda6 Mon Sep 17 00:00:00 2001 From: Morten Christensen Date: Mon, 30 Sep 2013 12:12:58 +0200 Subject: [PATCH] Fixing MemberType- and MemberRepository so properties, property types and property groups are properly initialized. --- src/Umbraco.Core/Models/MemberType.cs | 21 +++++ .../Models/Rdbms/PropertyTypeReadOnlyDto.cs | 2 +- .../Factories/MemberReadOnlyFactory.cs | 2 +- .../Factories/MemberTypeReadOnlyFactory.cs | 89 ++++++++++++------- .../Relators/PropertyDataRelator.cs | 2 + .../PropertyTypePropertyGroupRelator.cs | 3 +- .../Repositories/MemberRepository.cs | 10 +-- .../Repositories/MemberTypeRepository.cs | 2 +- .../Repositories/MemberRepositoryTest.cs | 26 ++++++ .../Entities/MockedContentTypes.cs | 27 ++++++ .../TestHelpers/Entities/MockedMember.cs | 26 ++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 12 files changed, 167 insertions(+), 44 deletions(-) create mode 100644 src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs diff --git a/src/Umbraco.Core/Models/MemberType.cs b/src/Umbraco.Core/Models/MemberType.cs index ed7d5cd3ab..2b32681392 100644 --- a/src/Umbraco.Core/Models/MemberType.cs +++ b/src/Umbraco.Core/Models/MemberType.cs @@ -114,5 +114,26 @@ namespace Umbraco.Core.Models MemberTypePropertyTypes.Add(propertyTypeAlias, tuple); } } + + /// + /// Method to call when Entity is being saved + /// + /// Created date is set and a Unique key is assigned + internal override void AddingEntity() + { + base.AddingEntity(); + + if (Key == Guid.Empty) + Key = Guid.NewGuid(); + } + + /// + /// Method to call when Entity is being updated + /// + /// Modified Date is set and a new Version guid is set + internal override void UpdatingEntity() + { + base.UpdatingEntity(); + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Rdbms/PropertyTypeReadOnlyDto.cs b/src/Umbraco.Core/Models/Rdbms/PropertyTypeReadOnlyDto.cs index 78e250a8b5..2f48035ba5 100644 --- a/src/Umbraco.Core/Models/Rdbms/PropertyTypeReadOnlyDto.cs +++ b/src/Umbraco.Core/Models/Rdbms/PropertyTypeReadOnlyDto.cs @@ -17,7 +17,7 @@ namespace Umbraco.Core.Models.Rdbms [Column("contentTypeId")] public int ContentTypeId { get; set; } - [Column("propertyTypeGroupId")] + [Column("PropertyTypesGroupId")] public int? PropertyTypeGroupId { get; set; } [Column("Alias")] diff --git a/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs index eb6e2c787d..09d4765eb3 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs @@ -61,7 +61,7 @@ namespace Umbraco.Core.Persistence.Factories ? propertyType.CreatePropertyFromValue(null) : propertyType.CreatePropertyFromRawValue(propertyDataDto.GetValue, propertyDataDto.VersionId, - propertyDataDto.Id); + propertyDataDto.PropertyDataId.Value); //on initial construction we don't want to have dirty properties tracked property.CreateDate = createDate; property.UpdateDate = createDate; diff --git a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs index e9e7fe19c4..925e0edccd 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs @@ -55,51 +55,72 @@ namespace Umbraco.Core.Persistence.Factories private PropertyGroupCollection GetPropertyTypeGroupCollection(MemberTypeReadOnlyDto dto, MemberType memberType) { - var propertyTypeGroupCollection = new PropertyGroupCollection(); - foreach (var propertyTypeGroup in dto.PropertyTypeGroups.Where(x => x.Id.HasValue)) + var propertyGroups = new PropertyGroupCollection(); + foreach (var groupDto in dto.PropertyTypeGroups.Where(x => x.Id.HasValue)) { - //Find PropertyTypes that belong to the current PropertyTypeGroup - var groupId = propertyTypeGroup.Id.Value; - var propertyTypesByGroup = - dto.PropertyTypes.Where( - x => x.Id.HasValue && x.PropertyTypeGroupId.HasValue && x.PropertyTypeGroupId.Value.Equals(groupId)); - //Create PropertyTypeCollection for passing into the PropertyTypeGroup, and loop through the above result to create PropertyTypes - var propertyTypeCollection = new PropertyTypeCollection(); - foreach (var propTypeDto in propertyTypesByGroup) + var group = new PropertyGroup(); + //Only assign an Id if the PropertyGroup belongs to this ContentType + if (groupDto.Id.HasValue && groupDto.Id == memberType.Id) { - //Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType - memberType.MemberTypePropertyTypes.Add(propTypeDto.Alias, - new Tuple(propTypeDto.CanEdit, propTypeDto.ViewOnProfile, propTypeDto.Id.Value)); - //PropertyType Collection - propertyTypeCollection.Add(new PropertyType(propTypeDto.ControlId, - propTypeDto.DbType.EnumParse(true)) - { - Alias = propTypeDto.Alias, - DataTypeDefinitionId = propTypeDto.DataTypeId, - Description = propTypeDto.Description, - HelpText = propTypeDto.HelpText, - Id = propTypeDto.Id.Value, - Mandatory = propTypeDto.Mandatory, - Name = propTypeDto.Name, - SortOrder = propTypeDto.SortOrder, - ValidationRegExp = propTypeDto.ValidationRegExp, - PropertyGroupId = new Lazy(() => propTypeDto.PropertyTypeGroupId.Value), - CreateDate = dto.CreateDate, - UpdateDate = dto.CreateDate - }); + group.Id = groupDto.Id.Value; + + if (groupDto.ParentGroupId.HasValue) + group.ParentId = groupDto.ParentGroupId.Value; + } + else + { + //If the PropertyGroup is inherited, we add a reference to the group as a Parent. + group.ParentId = groupDto.Id; } - var group = new PropertyGroup(propertyTypeCollection) {Id = groupId}; - propertyTypeGroupCollection.Add(@group); + group.Name = groupDto.Text; + group.SortOrder = groupDto.SortOrder; + group.PropertyTypes = new PropertyTypeCollection(); + + //Because we are likely to have a group with no PropertyTypes we need to ensure that these are excluded + var typeDtos = dto.PropertyTypes.Where(x => x.Id.HasValue && x.Id > 0 && x.PropertyTypeGroupId.HasValue && x.PropertyTypeGroupId.Value == groupDto.Id.Value); + foreach (var typeDto in typeDtos) + { + //Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType + memberType.MemberTypePropertyTypes.Add(typeDto.Alias, + new Tuple(typeDto.CanEdit, typeDto.ViewOnProfile, typeDto.Id.Value)); + + var tempGroupDto = groupDto; + var propertyType = new PropertyType(typeDto.ControlId, + typeDto.DbType.EnumParse(true)) + { + Alias = typeDto.Alias, + DataTypeDefinitionId = typeDto.DataTypeId, + Description = typeDto.Description, + Id = typeDto.Id.Value, + Name = typeDto.Name, + HelpText = typeDto.HelpText, + Mandatory = typeDto.Mandatory, + SortOrder = typeDto.SortOrder, + ValidationRegExp = typeDto.ValidationRegExp, + PropertyGroupId = new Lazy(() => tempGroupDto.Id.Value), + CreateDate = memberType.CreateDate, + UpdateDate = memberType.UpdateDate + }; + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + propertyType.ResetDirtyProperties(false); + group.PropertyTypes.Add(propertyType); + } + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + group.ResetDirtyProperties(false); + propertyGroups.Add(group); } - return propertyTypeGroupCollection; + + return propertyGroups; } private List GetPropertyTypes(MemberTypeReadOnlyDto dto, MemberType memberType) { //Find PropertyTypes that does not belong to a PropertyTypeGroup var propertyTypes = new List(); - foreach (var propertyType in dto.PropertyTypes.Where(x => x.PropertyTypeGroupId.HasValue == false && x.Id.HasValue)) + foreach (var propertyType in dto.PropertyTypes.Where(x => (x.PropertyTypeGroupId.HasValue == false || x.PropertyTypeGroupId.Value == 0) && x.Id.HasValue)) { //Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType memberType.MemberTypePropertyTypes.Add(propertyType.Alias, diff --git a/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs b/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs index 49c5e671e6..4eabe8c669 100644 --- a/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs +++ b/src/Umbraco.Core/Persistence/Relators/PropertyDataRelator.cs @@ -15,6 +15,8 @@ namespace Umbraco.Core.Persistence.Relators if (a == null) return Current; + p.VersionId = a.VersionId; + // Is this the same MemberReadOnlyDto as the current one we're processing if (Current != null && Current.UniqueId == a.UniqueId) { diff --git a/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs b/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs index e16a61db6f..a9129498c5 100644 --- a/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs +++ b/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using Umbraco.Core.Models.Rdbms; namespace Umbraco.Core.Persistence.Relators @@ -21,7 +22,7 @@ namespace Umbraco.Core.Persistence.Relators // Yes, just add this PropertyTypeReadOnlyDto to the current MemberTypeReadOnlyDto's collection Current.PropertyTypes.Add(p); - if(g.Id.HasValue) + if (g.Id.HasValue && Current.PropertyTypeGroups != null && Current.PropertyTypeGroups.Any(x => x.Id == g.Id.Value) == false) Current.PropertyTypeGroups.Add(g); // Return null to indicate we're not done with this MemberTypeReadOnlyDto yet diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs index 856ede87d1..caa92f94ef 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs @@ -229,10 +229,8 @@ namespace Umbraco.Core.Persistence.Repositories dto.NodeId = nodeDto.NodeId; Database.Insert(dto); - //TODO ContentType for the Member entity - //Create the PropertyData for this version - cmsPropertyData - /*var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id); + var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id); var propertyDataDtos = propertyFactory.BuildDto(((Member)entity).Properties); var keyDictionary = new Dictionary(); @@ -247,7 +245,7 @@ namespace Umbraco.Core.Persistence.Repositories foreach (var property in ((Member)entity).Properties) { property.Id = keyDictionary[property.PropertyTypeId]; - }*/ + } ((Member)entity).ResetDirtyProperties(); } @@ -300,7 +298,7 @@ namespace Umbraco.Core.Persistence.Repositories //TODO ContentType for the Member entity //Create the PropertyData for this version - cmsPropertyData - /*var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id); + var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id); var propertyDataDtos = propertyFactory.BuildDto(((Member)entity).Properties); var keyDictionary = new Dictionary(); @@ -325,7 +323,7 @@ namespace Umbraco.Core.Persistence.Repositories { property.Id = keyDictionary[property.PropertyTypeId]; } - }*/ + } ((ICanBeDirty)entity).ResetDirtyProperties(); } diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs index 305f828c2d..be3a9eb752 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs @@ -101,7 +101,7 @@ namespace Umbraco.Core.Persistence.Repositories sql.Select("umbracoNode.*", "cmsContentType.*", "cmsPropertyType.id AS PropertyTypeId", "cmsPropertyType.Alias", "cmsPropertyType.Name", "cmsPropertyType.Description", "cmsPropertyType.helpText", "cmsPropertyType.mandatory", "cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", - "cmsPropertyType.propertyTypeGroupId", "cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", + "cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId", "cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", "cmsDataType.controlId", "cmsDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId", "cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.parentGroupId", "cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder") diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs index 6aa9609807..6795f2c608 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Publishing; using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.Persistence.Repositories { @@ -174,6 +175,31 @@ namespace Umbraco.Tests.Persistence.Repositories } } + [Test] + public void MemberRepository_Can_Persist_Member() + { + IMember sut; + var unitOfWork = UnitOfWorkProvider.GetUnitOfWork(); + MemberTypeRepository memberTypeRepository; + using (var repository = CreateRepository(unitOfWork, out memberTypeRepository)) + { + var memberType = MockedContentTypes.CreateSimpleMemberType(); + memberTypeRepository.AddOrUpdate(memberType); + unitOfWork.Commit(); + + var member = MockedMember.CreateSimpleContent(memberType, "Johnny Hefty", "johnny@example.com", "123", "hefty", -1); + repository.AddOrUpdate(member); + unitOfWork.Commit(); + + sut = repository.Get(member.Id); + + Assert.That(sut, Is.Not.Null); + Assert.That(sut.ContentType.PropertyGroups.Count(), Is.EqualTo(1)); + Assert.That(sut.ContentType.PropertyTypes.Count(), Is.EqualTo(12)); + Assert.That(sut.Properties.Count(), Is.EqualTo(12)); + } + } + [Test] public void Can_Create_Correct_Subquery() { diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index f3f09e5fae..cc22ce913b 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -265,5 +265,32 @@ namespace Umbraco.Tests.TestHelpers.Entities return mediaType; } + + public static MemberType CreateSimpleMemberType() + { + var contentType = new MemberType(-1) + { + Alias = "simple", + Name = "Simple Page", + Description = "ContentType used for simple text pages", + 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 }); + + //ensure that nothing is marked as dirty + contentType.ResetDirtyProperties(false); + + return contentType; + } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs new file mode 100644 index 0000000000..4aeb406811 --- /dev/null +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedMember.cs @@ -0,0 +1,26 @@ +using Umbraco.Core.Models; + +namespace Umbraco.Tests.TestHelpers.Entities +{ + public class MockedMember + { + public static Member CreateSimpleContent(IMemberType contentType, string name, string email, string password, string username, int parentId) + { + var member = new Member(name, parentId, contentType, new PropertyCollection()) + { + CreatorId = 0, + Email = email, + Password = password, + Username = username + }; + + member.SetValue("title", name + " member"); + member.SetValue("bodyText", "This is a subpage"); + member.SetValue("author", "John Doe"); + + member.ResetDirtyProperties(false); + + return member; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index a37a253e9b..469caa926c 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -301,6 +301,7 @@ +