From 2d2feb86bbbd5c14ad1c4c6471ac278a3c5ffab7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 26 Mar 2021 00:22:11 +1100 Subject: [PATCH] Starts converting member macros --- .../Security/IUmbracoWebsiteSecurity.cs | 8 -- .../Security/RegisterMemberStatus.cs | 13 -- .../Security/MembersIdentityUser.cs | 2 + .../Security/UmbracoWebsiteSecurity.cs | 5 - .../Controllers/UmbRegisterController.cs | 122 +++++++++++------- 5 files changed, 80 insertions(+), 70 deletions(-) delete mode 100644 src/Umbraco.Core/Security/RegisterMemberStatus.cs diff --git a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs index 10fb9b5f2c..8cdb1d61c7 100644 --- a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs +++ b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs @@ -14,14 +14,6 @@ namespace Umbraco.Cms.Core.Security /// Instance of RegisterModel CreateRegistrationModel(string memberTypeAlias = null); - /// - /// Registers a new member. - /// - /// Register member model. - /// Flag for whether to log the member in upon successful registration. - /// Result of registration operation. - Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true); - /// /// Creates a new profile model filled in with the current members details if they are logged in which allows for editing /// profile properties. diff --git a/src/Umbraco.Core/Security/RegisterMemberStatus.cs b/src/Umbraco.Core/Security/RegisterMemberStatus.cs deleted file mode 100644 index 757cfb3ba2..0000000000 --- a/src/Umbraco.Core/Security/RegisterMemberStatus.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Umbraco.Cms.Core.Security -{ - public enum RegisterMemberStatus - { - Success, - InvalidUserName, - InvalidPassword, - InvalidEmail, - DuplicateUserName, - DuplicateEmail, - Error, - } -} diff --git a/src/Umbraco.Infrastructure/Security/MembersIdentityUser.cs b/src/Umbraco.Infrastructure/Security/MembersIdentityUser.cs index 6e3473c3ce..1f01cecf0d 100644 --- a/src/Umbraco.Infrastructure/Security/MembersIdentityUser.cs +++ b/src/Umbraco.Infrastructure/Security/MembersIdentityUser.cs @@ -125,5 +125,7 @@ namespace Umbraco.Cms.Core.Security public string MemberTypeAlias { get; set; } private static string UserIdToString(int userId) => string.Intern(userId.ToString()); + + // TODO: Should we support custom member properties for persistence/retrieval? } } diff --git a/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurity.cs b/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurity.cs index 5a67f6f484..b6dce007ed 100644 --- a/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurity.cs +++ b/src/Umbraco.Web.Common/Security/UmbracoWebsiteSecurity.cs @@ -111,11 +111,6 @@ namespace Umbraco.Cms.Web.Common.Security return viewProperties; } - public Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true) - { - throw new NotImplementedException(); - } - /// public async Task GetCurrentMemberProfileModelAsync() { diff --git a/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs index d5accbc086..50a57fbfba 100644 --- a/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs +++ b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs @@ -1,8 +1,11 @@ -using System; +using System; +using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Security; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Security; @@ -10,20 +13,29 @@ using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Web.Common.Filters; +using Umbraco.Cms.Web.Common.Security; using Umbraco.Extensions; namespace Umbraco.Cms.Web.Website.Controllers { public class UmbRegisterController : SurfaceController { - private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; + private readonly MemberManager _memberManager; + private readonly IMemberService _memberService; - public UmbRegisterController(IUmbracoContextAccessor umbracoContextAccessor, - IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, - IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + public UmbRegisterController( + MemberManager memberManager, + IMemberService memberService, + IUmbracoContextAccessor umbracoContextAccessor, + IUmbracoDatabaseFactory databaseFactory, + ServiceContext services, + AppCaches appCaches, + IProfilingLogger profilingLogger, + IPublishedUrlProvider publishedUrlProvider) : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) { - _websiteSecurityAccessor = websiteSecurityAccessor; + _memberManager = memberManager; + _memberService = memberService; } [HttpPost] @@ -43,52 +55,74 @@ namespace Umbraco.Cms.Web.Website.Controllers model.Name = model.Email; } - var result = await _websiteSecurityAccessor.WebsiteSecurity.RegisterMemberAsync(model, model.LoginOnSuccess); - - switch (result) + IdentityResult result = await RegisterMemberAsync(model, model.LoginOnSuccess); + if (result.Succeeded) { - case RegisterMemberStatus.Success: + TempData["FormSuccess"] = true; - TempData["FormSuccess"] = true; + // If there is a specified path to redirect to then use it. + if (model.RedirectUrl.IsNullOrWhiteSpace() == false) + { + return Redirect(model.RedirectUrl); + } - // If there is a specified path to redirect to then use it. - if (model.RedirectUrl.IsNullOrWhiteSpace() == false) + // Redirect to current page by default. + return RedirectToCurrentUmbracoPage(); + } + else + { + AddModelErrors(result, "registerModel"); + return CurrentUmbracoPage(); + } + } + + private void AddModelErrors(IdentityResult result, string prefix = "") + { + foreach (IdentityError error in result.Errors) + { + ModelState.AddModelError(prefix, error.Description); + } + } + + /// + /// Registers a new member. + /// + /// Register member model. + /// Flag for whether to log the member in upon successful registration. + /// Result of registration operation. + private async Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true) + { + model.Username = (model.UsernameIsEmail || model.Username == null) ? model.Email : model.Username; + + var identityUser = MembersIdentityUser.CreateNew(model.Username, model.Email, model.MemberTypeAlias, model.Name); + IdentityResult identityResult = await _memberManager.CreateAsync( + identityUser, + model.Password); + + if (identityResult.Succeeded) + { + // Update the custom properties + // TODO: See TODO in MembersIdentityUser, Should we support custom member properties for persistence/retrieval? + IMember member = _memberService.GetByUsername(identityUser.UserName); + if (model.MemberProperties != null) + { + foreach (UmbracoProperty property in model.MemberProperties.Where(p => p.Value != null) + .Where(property => member.Properties.Contains(property.Alias))) { - return Redirect(model.RedirectUrl); + member.Properties[property.Alias].SetValue(property.Value); } + } + _memberService.Save(member); - // Redirect to current page by default. - return RedirectToCurrentUmbracoPage(); - case RegisterMemberStatus.InvalidUserName: - ModelState.AddModelError((model.UsernameIsEmail || model.Username == null) - ? "registerModel.Email" - : "registerModel.Username", - "Username is not valid"); - break; - case RegisterMemberStatus.InvalidPassword: - ModelState.AddModelError("registerModel.Password", "The password is not strong enough"); - break; - case RegisterMemberStatus.InvalidEmail: - ModelState.AddModelError("registerModel.Email", "Email is invalid"); - break; - case RegisterMemberStatus.DuplicateUserName: - ModelState.AddModelError((model.UsernameIsEmail || model.Username == null) - ? "registerModel.Email" - : "registerModel.Username", - "A member with this username already exists."); - break; - case RegisterMemberStatus.DuplicateEmail: - ModelState.AddModelError("registerModel.Email", "A member with this e-mail address already exists"); - break; - case RegisterMemberStatus.Error: - // Don't add a field level error, just model level. - ModelState.AddModelError("registerModel", $"An error occurred creating the member: {result}"); - break; - default: - throw new ArgumentOutOfRangeException(); + if (logMemberIn) + { + // TODO: Log them in + throw new NotImplementedException("Implement MemberSignInManager"); + } } - return CurrentUmbracoPage(); + return identityResult; + } } }