From 6fefcacc61e740203203bf57e3b3ddfa51c214ce Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 28 Jan 2014 18:59:27 +1100 Subject: [PATCH] Adds more methods to the MembershipHelper, updates the RegisterModel and obsoletes the standard ctor so biz logic is not happening in the model, updates the snippets to use the correct way. Fixes an issue in the membership repo for persisting new members when the member type doesn't contain all the built-in props. --- .../Repositories/MemberRepository.cs | 17 +++--- .../PartialViewMacros/Templates/Login.cshtml | 1 + .../Templates/LoginStatus.cshtml | 3 +- .../Templates/RegisterMember.cshtml | 17 +++--- .../PartialViews/Templates/Login.cshtml | 1 + .../PartialViews/Templates/LoginStatus.cshtml | 3 +- .../Templates/RegisterMember.cshtml | 17 +++--- .../Controllers/UmbRegisterController.cs | 2 +- src/Umbraco.Web/Models/LoginStatusModel.cs | 2 +- src/Umbraco.Web/Models/RegisterModel.cs | 53 +++++++++++-------- src/Umbraco.Web/Models/UmbracoProperty.cs | 3 ++ src/Umbraco.Web/Security/MembershipHelper.cs | 35 ++++++++++++ 12 files changed, 105 insertions(+), 49 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs index ae76216800..4bdadbe99b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs @@ -237,7 +237,12 @@ namespace Umbraco.Core.Persistence.Repositories //Create the PropertyData for this version - cmsPropertyData var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id); - var propertyDataDtos = propertyFactory.BuildDto(((Member)entity).Properties); + //Add Properties + // - don't try to save the property if it doesn't exist (or doesn't have an ID) on the content type + // - this can occur if the member type doesn't contain the built-in properties that the + // - member object contains. + var propsToPersist = entity.Properties.Where(x => x.PropertyType.HasIdentity).ToArray(); + var propertyDataDtos = propertyFactory.BuildDto(propsToPersist); var keyDictionary = new Dictionary(); //Add Properties @@ -248,7 +253,7 @@ namespace Umbraco.Core.Persistence.Repositories } //Update Properties with its newly set Id - foreach (var property in ((Member)entity).Properties) + foreach (var property in propsToPersist) { property.Id = keyDictionary[property.PropertyTypeId]; } @@ -331,12 +336,10 @@ namespace Umbraco.Core.Persistence.Repositories //Add Properties // - don't try to save the property if it doesn't exist (or doesn't have an ID) on the content type // - this can occur if the member type doesn't contain the built-in properties that the - // - member object contains. - var existingProperties = entity.Properties - .Where(property => entity.ContentType.PropertyTypes.Any(x => x.Alias == property.Alias && x.HasIdentity)) - .ToList(); + // - member object contains. + var propsToPersist = entity.Properties.Where(x => x.PropertyType.HasIdentity).ToArray(); - var propertyDataDtos = propertyFactory.BuildDto(existingProperties); + var propertyDataDtos = propertyFactory.BuildDto(propsToPersist); foreach (var propertyDataDto in propertyDataDtos) { diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml index b73669ff51..52184e8c73 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/Login.cshtml @@ -16,6 +16,7 @@ Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); } +@*NOTE: This RenderJsHere code should be put on your main template page where the rest of your script tags are placed*@ @Html.RenderJsHere() @using (Html.BeginUmbracoForm("HandleLogin")) diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/LoginStatus.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/LoginStatus.cshtml index 7d8a1ea609..25b5e7eadd 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/LoginStatus.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/LoginStatus.cshtml @@ -5,7 +5,7 @@ @using Umbraco.Web.Controllers @{ - var loginStatusModel = new LoginStatusModel(); + var loginStatusModel = Members.GetCurrentLoginStatus(); Html.EnableClientValidation(); Html.EnableUnobtrusiveJavaScript(); @@ -14,6 +14,7 @@ Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); } +@*NOTE: This RenderJsHere code should be put on your main template page where the rest of your script tags are placed*@ @Html.RenderJsHere() @if (loginStatusModel.IsLoggedIn) diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/RegisterMember.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/RegisterMember.cshtml index 386a9ad97c..a978ed7332 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/RegisterMember.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/RegisterMember.cshtml @@ -7,7 +7,7 @@ @using Umbraco.Web.Controllers @{ - var registerModel = new RegisterModel(); + var registerModel = Members.CreateRegistrationModel(); @* Configurable here: @@ -38,6 +38,9 @@ var success = TempData["FormSuccess"] != null; } +@*NOTE: This RenderJsHere code should be put on your main template page where the rest of your script tags are placed*@ +@Html.RenderJsHere() + @if (success) { // This message will show if RedirectOnSucces is set to false (default) @@ -68,11 +71,11 @@ else
@if (registerModel.MemberProperties != null) { - for (var i = 0; i < registerModel.MemberProperties.Count; i++) + foreach (var prop in registerModel.MemberProperties) { - @Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name) - @Html.EditorFor(m => registerModel.MemberProperties[i].Value) - @Html.HiddenFor(m => registerModel.MemberProperties[i].Alias) + @Html.LabelFor(m => prop.Value, prop.Name) + @Html.EditorFor(m => prop.Value) + @Html.HiddenFor(m => prop.Alias)
} } @@ -83,8 +86,6 @@ else @Html.HiddenFor(m => registerModel.UsernameIsEmail) - - - @Html.RenderJsHere() + } } \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml index 1e2bb759cb..89fa40c8ba 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml @@ -16,6 +16,7 @@ Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); } +@*NOTE: This RenderJsHere code should be put on your main template page where the rest of your script tags are placed*@ @Html.RenderJsHere() @using (Html.BeginUmbracoForm("HandleLogin")) diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml index f0d62be7b6..f48a4e5d2a 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml @@ -6,7 +6,7 @@ @using Umbraco.Web.Controllers @{ - var loginStatusModel = new LoginStatusModel(); + var loginStatusModel = Members.GetCurrentLoginStatus(); Html.EnableClientValidation(); Html.EnableUnobtrusiveJavaScript(); @@ -15,6 +15,7 @@ Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); } +@*NOTE: This RenderJsHere code should be put on your main template page where the rest of your script tags are placed*@ @Html.RenderJsHere() @if (loginStatusModel.IsLoggedIn) diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml index 9a18684f13..1243d1b604 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml @@ -7,7 +7,7 @@ @using Umbraco.Web.Controllers @{ - var registerModel = new RegisterModel(); + var registerModel = Members.CreateRegistrationModel(); @* Configurable here: @@ -38,6 +38,9 @@ var success = TempData["FormSuccess"] != null; } +@*NOTE: This RenderJsHere code should be put on your main template page where the rest of your script tags are placed*@ +@Html.RenderJsHere() + @if (success) { // This message will show if RedirectOnSucces is set to false (default) @@ -67,12 +70,12 @@ else @Html.ValidationMessageFor(m => registerModel.Password)
- @if (registerModel.MemberProperties != null) { - for (var i = 0; i < registerModel.MemberProperties.Count; i++) + @if (registerModel.MemberProperties != null) { + foreach (var prop in registerModel.MemberProperties) { - @Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name) - @Html.EditorFor(m => registerModel.MemberProperties[i].Value) - @Html.HiddenFor(m => registerModel.MemberProperties[i].Alias) + @Html.LabelFor(m => prop.Value, prop.Name) + @Html.EditorFor(m => prop.Value) + @Html.HiddenFor(m => prop.Alias)
} } @@ -84,7 +87,5 @@ else - - @Html.RenderJsHere() } } \ No newline at end of file diff --git a/src/Umbraco.Web/Controllers/UmbRegisterController.cs b/src/Umbraco.Web/Controllers/UmbRegisterController.cs index 7f943435c2..e7ca7facae 100644 --- a/src/Umbraco.Web/Controllers/UmbRegisterController.cs +++ b/src/Umbraco.Web/Controllers/UmbRegisterController.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web.Controllers MembershipCreateStatus status; var member = Membership.CreateUser(model.Username, model.Password, model.Email, //TODO: Support q/a http://issues.umbraco.org/issue/U4-3213 - "", "", + null, null, true, out status); switch (status) diff --git a/src/Umbraco.Web/Models/LoginStatusModel.cs b/src/Umbraco.Web/Models/LoginStatusModel.cs index 5c97aec6cb..bc36a42202 100644 --- a/src/Umbraco.Web/Models/LoginStatusModel.cs +++ b/src/Umbraco.Web/Models/LoginStatusModel.cs @@ -39,7 +39,7 @@ namespace Umbraco.Web.Models /// /// This will construct a new LoginStatusModel and perform a lookup for hte curently logged in member /// - [Obsolete("Do not use this ctor as it will perform business logic lookups. Use the MembershipHelper.GetLoginStatusModel or the static LoginStatusModel.CreateModel() to create an empty model.")] + [Obsolete("Do not use this ctor as it will perform business logic lookups. Use the MembershipHelper.GetCurrentLoginStatus or the static LoginStatusModel.CreateModel() to create an empty model.")] public LoginStatusModel() : this(true) { diff --git a/src/Umbraco.Web/Models/RegisterModel.cs b/src/Umbraco.Web/Models/RegisterModel.cs index c71edf7f77..66218a363e 100644 --- a/src/Umbraco.Web/Models/RegisterModel.cs +++ b/src/Umbraco.Web/Models/RegisterModel.cs @@ -1,46 +1,55 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Web; using umbraco.cms.businesslogic.member; using Umbraco.Core; +using Umbraco.Web.Security; namespace Umbraco.Web.Models { public class RegisterModel { - public RegisterModel() + /// + /// Creates a new empty RegisterModel + /// + /// + public static RegisterModel CreateModel() { - this.MemberTypeAlias = Constants.Conventions.MemberTypes.Member; + var model = new RegisterModel(false); + return model; + } - this.RedirectOnSucces = false; + private RegisterModel(bool doLookup) + { + MemberTypeAlias = Constants.Conventions.MemberTypes.Member; + RedirectOnSucces = false; + RedirectUrl = "/"; + UsernameIsEmail = true; - this.RedirectUrl = "/"; - - this.UsernameIsEmail = true; - - var memberType = MemberType.GetByAlias(this.MemberTypeAlias); - - if (memberType != null) + if (doLookup && HttpContext.Current != null && ApplicationContext.Current != null) { - this.MemberProperties = new List(); - - foreach (var prop in memberType.PropertyTypes.Where(memberType.MemberCanEdit)) - { - this.MemberProperties.Add(new UmbracoProperty - { - Alias = prop.Alias, - Name = prop.Name, - Value = string.Empty - }); - } + var helper = new MembershipHelper(ApplicationContext.Current, new HttpContextWrapper(HttpContext.Current)); + var model = helper.CreateRegistrationModel(MemberTypeAlias); + MemberProperties = model.MemberProperties; } } + [Obsolete("Do not use this ctor as it will perform business logic lookups. Use the MembershipHelper.CreateRegistrationModel or the static RegisterModel.CreateModel() to create an empty model.")] + public RegisterModel() + : this(true) + { + } + [Required] [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", ErrorMessage = "Please enter a valid e-mail address")] public string Email { get; set; } + /// + /// Returns the member properties + /// public List MemberProperties { get; set; } public string MemberTypeAlias { get; set; } diff --git a/src/Umbraco.Web/Models/UmbracoProperty.cs b/src/Umbraco.Web/Models/UmbracoProperty.cs index cb81829cee..ad907df1a0 100644 --- a/src/Umbraco.Web/Models/UmbracoProperty.cs +++ b/src/Umbraco.Web/Models/UmbracoProperty.cs @@ -1,5 +1,8 @@ namespace Umbraco.Web.Models { + /// + /// A simple representation of an Umbraco property + /// public class UmbracoProperty { public string Alias { get; set; } diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs index 53a0e9906d..a2b31bae50 100644 --- a/src/Umbraco.Web/Security/MembershipHelper.cs +++ b/src/Umbraco.Web/Security/MembershipHelper.cs @@ -37,6 +37,41 @@ namespace Umbraco.Web.Security } #endregion + /// + /// Creates a model to use for registering new members with custom member properties + /// + /// + /// + public RegisterModel CreateRegistrationModel(string memberTypeAlias = null) + { + if (Membership.Provider.IsUmbracoMembershipProvider()) + { + memberTypeAlias = memberTypeAlias ?? Constants.Conventions.MemberTypes.Member; + var memberType = _applicationContext.Services.MemberTypeService.Get(memberTypeAlias); + if (memberType == null) + throw new InvalidOperationException("Could not find a member type with alias " + memberTypeAlias); + + var props = memberType.PropertyTypes + .Where(x => memberType.MemberCanEditProperty(x.Alias)) + .Select(prop => new UmbracoProperty + { + Alias = prop.Alias, + Name = prop.Name, + Value = string.Empty + }).ToList(); + + var model = RegisterModel.CreateModel(); + model.MemberProperties = props; + return model; + } + else + { + var model = RegisterModel.CreateModel(); + model.MemberTypeAlias = string.Empty; + return model; + } + } + /// /// Returns the login status model of the currently logged in member, if no member is logged in it returns null; ///