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