From 953c711ca4161e25985ced286d1c29531d017289 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 18 Feb 2014 17:19:38 +1100 Subject: [PATCH] Updates the default member type property types to use "Labels", then needed to update the member type repo and membertypereadonlyfactory to ensure that even though the underlying data type for the property exposes a different Db Type that we 'reset' that Db Type to what it always should be. This means that no matter what underlying data type a developer changes a property to, if it is a built-in membership property, the Db Type will always stay consistent and save in the correct column. Of course if someone enters some invalid data, then the data will not be saved. --- src/Umbraco.Core/Constants-Conventions.cs | 8 ++-- .../Factories/MemberTypeReadOnlyFactory.cs | 10 +++- .../Repositories/MemberTypeRepository.cs | 46 ++++++++++++++++++- .../Services/MemberServiceTests.cs | 19 ++++++++ 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs index 7425cdf640..2f3a6f36ed 100644 --- a/src/Umbraco.Core/Constants-Conventions.cs +++ b/src/Umbraco.Core/Constants-Conventions.cs @@ -185,7 +185,7 @@ namespace Umbraco.Core }, { FailedPasswordAttempts, - new PropertyType(new Guid(PropertyEditors.Integer), DataTypeDatabaseType.Integer) + new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType.Integer) { Alias = FailedPasswordAttempts, Name = FailedPasswordAttemptsLabel @@ -209,7 +209,7 @@ namespace Umbraco.Core }, { LastLockoutDate, - new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date) + new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Date) { Alias = LastLockoutDate, Name = LastLockoutDateLabel @@ -217,7 +217,7 @@ namespace Umbraco.Core }, { LastLoginDate, - new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date) + new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Date) { Alias = LastLoginDate, Name = LastLoginDateLabel @@ -225,7 +225,7 @@ namespace Umbraco.Core }, { LastPasswordChangeDate, - new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date) + new PropertyType(new Guid(PropertyEditors.NoEdit), DataTypeDatabaseType.Date) { Alias = LastPasswordChangeDate, Name = LastPasswordChangeDateLabel diff --git a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs index aaa2183eb6..8f0ce1ecbe 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.Repositories; namespace Umbraco.Core.Persistence.Factories { @@ -87,8 +88,11 @@ namespace Umbraco.Core.Persistence.Factories new Tuple(typeDto.CanEdit, typeDto.ViewOnProfile, typeDto.Id.Value)); var tempGroupDto = groupDto; - var propertyType = new PropertyType(typeDto.ControlId, - typeDto.DbType.EnumParse(true)) + + var propertyType = new PropertyType(typeDto.ControlId, + //ensures that any built-in membership properties have their correct dbtype assigned no matter + //what the underlying data type is + MemberTypeRepository.GetDbTypeForProperty(typeDto.Alias, typeDto.DbType.EnumParse(true))) { Alias = typeDto.Alias, DataTypeDefinitionId = typeDto.DataTypeId, @@ -117,6 +121,8 @@ namespace Umbraco.Core.Persistence.Factories return propertyGroups; } + + private List GetPropertyTypes(MemberTypeReadOnlyDto dto, MemberType memberType) { //Find PropertyTypes that does not belong to a PropertyTypeGroup diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs index 48e0178392..74c885936d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs @@ -180,6 +180,8 @@ namespace Umbraco.Core.Persistence.Repositories PersistNewBaseContentType(dto, entity); + EnsureCorrectDbTypeForBuiltInProperties(entity); + //Handles the MemberTypeDto (cmsMemberType table) var memberTypeDtos = factory.BuildMemberTypeDtos(entity); foreach (var memberTypeDto in memberTypeDtos) @@ -213,6 +215,8 @@ namespace Umbraco.Core.Persistence.Repositories PersistUpdatedBaseContentType(dto, entity); + EnsureCorrectDbTypeForBuiltInProperties(entity); + //Remove existing entries before inserting new ones Database.Delete("WHERE NodeId = @Id", new {Id = entity.Id}); @@ -228,7 +232,25 @@ namespace Umbraco.Core.Persistence.Repositories #endregion - private IEnumerable BuildFromDtos(List dtos) + /// + /// now we need to ensure that all the built-in membership provider properties have their correct db types + /// assigned, no matter what the underlying data type is + /// + /// + private static void EnsureCorrectDbTypeForBuiltInProperties(IContentTypeBase memberType) + { + foreach (var propertyType in memberType.PropertyTypes) + { + propertyType.DataTypeDatabaseType = GetDbTypeForProperty(propertyType.Alias, propertyType.DataTypeDatabaseType); + } + } + + /// + /// Builds a collection of entities from a collection of Dtos + /// + /// + /// + private static IEnumerable BuildFromDtos(List dtos) { if (dtos == null || dtos.Any() == false) return Enumerable.Empty(); @@ -236,5 +258,27 @@ namespace Umbraco.Core.Persistence.Repositories var factory = new MemberTypeReadOnlyFactory(); return dtos.Select(factory.BuildEntity); } + + /// + /// If this is one of our internal properties - we will manually assign the data type since they must + /// always correspond to the correct db type no matter what the backing data type is assigned. + /// + /// + /// + /// + internal static DataTypeDatabaseType GetDbTypeForProperty(string propAlias, DataTypeDatabaseType dbType) + { + var stdProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); + var aliases = stdProps.Select(x => x.Key).ToArray(); + + //check if it is built in + if (aliases.Contains(propAlias)) + { + //return the pre-determined db type for this property + return stdProps.Single(x => x.Key == propAlias).Value.DataTypeDatabaseType; + } + + return dbType; + } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs index 9c70047b20..7ad39e8599 100644 --- a/src/Umbraco.Tests/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberServiceTests.cs @@ -905,5 +905,24 @@ namespace Umbraco.Tests.Services Assert.AreEqual(5, found); } + [Test] + public void Setting_Property_On_Built_In_Member_Property_When_Property_Doesnt_Exist_On_Type_Is_Ok() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + memberType.RemovePropertyType(Constants.Conventions.Member.Comments); + ServiceContext.MemberTypeService.Save(memberType); + Assert.IsFalse(memberType.PropertyTypes.Any(x => x.Alias == Constants.Conventions.Member.Comments)); + + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + //this should not throw an exception + customMember.Comments = "hello world"; + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.GetById(customMember.Id); + + Assert.AreEqual(string.Empty, found.Comments); + } + } } \ No newline at end of file