Skip to content

Commit

Permalink
Merge pull request #16 from umbraco/members
Browse files Browse the repository at this point in the history
Added macros and Controllers for login and register
  • Loading branch information
Jeavon authored Dec 5, 2022
2 parents def3fef + e288fa3 commit 0ed255c
Show file tree
Hide file tree
Showing 10 changed files with 416 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
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.Routing;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Security;
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.Cms.Web.Website.Controllers;
using Umbraco.Cms.Web.Website.Models;

namespace Umbraco.Docs.Samples.Web.Controllers
{
public class UmbAlternativeRegisterController : SurfaceController
{
private readonly IMemberManager _memberManager;
private readonly IMemberService _memberService;
private readonly IMemberSignInManager _memberSignInManager;
private readonly ICoreScopeProvider _coreScopeProvider;

public UmbAlternativeRegisterController(
IMemberManager memberManager,
IMemberService memberService,
IUmbracoContextAccessor umbracoContextAccessor,
IUmbracoDatabaseFactory databaseFactory,
ServiceContext services,
AppCaches appCaches,
IProfilingLogger profilingLogger,
IPublishedUrlProvider publishedUrlProvider,
IMemberSignInManager memberSignInManager,
ICoreScopeProvider coreScopeProvider)
: base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider)
{
_memberManager = memberManager;
_memberService = memberService;
_memberSignInManager = memberSignInManager;
_coreScopeProvider = coreScopeProvider;
}

[HttpPost]
[ValidateAntiForgeryToken]
[ValidateUmbracoFormRouteString]
public async Task<IActionResult> HandleRegisterMember([Bind(Prefix = "registerModel")] RegisterModel model)
{
if (ModelState.IsValid == false)
{
return CurrentUmbracoPage();
}

MergeRouteValuesToModel(model);

IdentityResult result = await RegisterMemberAsync(model);
if (result.Succeeded)
{
TempData["FormSuccess"] = true;


if (model.RedirectUrl.IsNullOrWhiteSpace() == false)
{
return Redirect(model.RedirectUrl!);
}


return RedirectToCurrentUmbracoPage();
}

AddErrors(result);
return CurrentUmbracoPage();
}

/// <summary>
///
/// </summary>
/// <param name="model"></param>
private void MergeRouteValuesToModel(RegisterModel model)
{
if (RouteData.Values.TryGetValue(nameof(RegisterModel.RedirectUrl), out var redirectUrl) && redirectUrl != null)
{
model.RedirectUrl = redirectUrl.ToString();
}

if (RouteData.Values.TryGetValue(nameof(RegisterModel.MemberTypeAlias), out var memberTypeAlias) &&
memberTypeAlias != null)
{
model.MemberTypeAlias = memberTypeAlias.ToString()!;
}

if (RouteData.Values.TryGetValue(nameof(RegisterModel.UsernameIsEmail), out var usernameIsEmail) &&
usernameIsEmail != null)
{
model.UsernameIsEmail = usernameIsEmail.ToString() == "True";
}
}

private void AddErrors(IdentityResult result)
{
foreach (IdentityError? error in result.Errors)
{
ModelState.AddModelError("registerModel", error.Description);
}
}

//Here we created a helper Method to assign a MemberGroup to a member.
private void AssignMemberGroup(string email, string group)
{
try
{
_memberService.AssignRole(email, group);
}
catch (Exception ex)
{
//handle the exception
}

}


/// <summary>

/// </summary>
/// <param name="model">Register member model.</param>
/// <param name="logMemberIn">Flag for whether to log the member in upon successful registration.</param>
/// <returns>Result of registration operation.</returns>
private async Task<IdentityResult> RegisterMemberAsync(RegisterModel model, bool logMemberIn = true)
{
using ICoreScope scope = _coreScopeProvider.CreateCoreScope(autoComplete: true);


if (string.IsNullOrEmpty(model.Name) && string.IsNullOrEmpty(model.Email) == false)
{
model.Name = model.Email;
}

model.Username = model.UsernameIsEmail || model.Username == null ? model.Email : model.Username;

var identityUser =
MemberIdentityUser.CreateNew(model.Username, model.Email, model.MemberTypeAlias, true, model.Name);
IdentityResult identityResult = await _memberManager.CreateAsync(
identityUser,
model.Password);

if (identityResult.Succeeded)
{

IMember? member = _memberService.GetByKey(identityUser.Key);
if (member == null)
{

throw new InvalidOperationException($"Could not find a member with key: {member?.Key}.");
}

foreach (MemberPropertyModel property in model.MemberProperties.Where(p => p.Value != null).Where(property => member.Properties.Contains(property.Alias)))
{
member.Properties[property.Alias]?.SetValue(property.Value);
}

//Before we save the member we make sure to assign the group, for this the "Group" must exist in the backoffice.
string memberGroup = "professionals";
AssignMemberGroup(model.Email, memberGroup);

_memberService.Save(member);

if (logMemberIn)
{
await _memberSignInManager.SignInAsync(identityUser, false);
}
}

return identityResult;
}
}
}
4 changes: 4 additions & 0 deletions Umbraco.Docs.Samples.Web/Views/ContentPage.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@


<section class="section">

<div class="container">
<h1><a href="">Members</a></h1>
</div>

<div class="container">
<h1><a href="https://our.umbraco.com/Documentation/Reference/Querying/IPublishedContent/Properties/index-v9">Cheat sheet - Standard Model Properties</a></h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@
@{
var startNodeId = Model.MacroParameters["startNodeId"] ?? Model.Content.Id;

var numberOfPosts = 3;
if (Model.MacroParameters["numberOfPosts"] != null)
{
int.TryParse((string)Model.MacroParameters["numberOfPosts"], out numberOfPosts);
}

var numberOfMorePosts = Model.GetParameterValue<int>("numberOfPosts");
}

@if (startNodeId != null)
Expand All @@ -35,7 +32,7 @@

//Gets all blogposts to calculate pages
var blogposts = startNode.Children.OrderBy(x => x.CreateDate).ToList();
var pageCount = (int)Math.Ceiling((double)blogposts.Count / (double)numberOfPosts);
var pageCount = (int)Math.Ceiling((double)blogposts.Count / (double)numberOfMorePosts);
//gets the page from the querystring and sets it to one if it is out of range
var page = 1;
if (httpContext != null && !string.IsNullOrEmpty(httpContext.Request.Query["page"]))
Expand All @@ -47,7 +44,7 @@
}
}
//Gets the blogposts for the current page
var pagedBlogposts = blogposts.Skip((page - 1) * numberOfPosts).Take(numberOfPosts).ToList();
var pagedBlogposts = blogposts.Skip((page - 1) * numberOfMorePosts).Take(numberOfMorePosts).ToList();

if (pagedBlogposts.Count > 0)
{
Expand All @@ -69,7 +66,7 @@
</div>
}

if (blogposts.Count > numberOfPosts)
if (blogposts.Count > numberOfMorePosts)
{
<div class="pagination">
<nav class="nav-bar nav-bar--center">
Expand Down
108 changes: 108 additions & 0 deletions Umbraco.Docs.Samples.Web/Views/MacroPartials/Login.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
@inherits Umbraco.Cms.Web.Common.Macros.PartialViewMacroPage


@using Umbraco.Cms.Web.Common.Models
@using Umbraco.Cms.Web.Common.Security
@using Umbraco.Cms.Web.Website.Controllers
@using Umbraco.Cms.Core.Services
@using Umbraco.Extensions
@inject IMemberExternalLoginProviders memberExternalLoginProviders
@inject ITwoFactorLoginService twoFactorLoginService
@{
var loginModel = new LoginModel();
// You can modify this to redirect to a different URL instead of the current one
loginModel.RedirectUrl = null;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>


@if (ViewData.TryGetTwoFactorProviderNames(out var providerNames))
{

foreach (var providerName in providerNames)
{
<div class="2fa-form">
<h4>Two factor with @providerName.</h4>
<div asp-validation-summary="All" class="text-danger"></div>
@using (Html.BeginUmbracoForm<UmbTwoFactorLoginController>(nameof(UmbTwoFactorLoginController.Verify2FACode)))
{

<text>
<input type="hidden" name="provider" value="@providerName"/>
Input security code: <input name="code" value=""/><br/>
<button type="submit" class="btn btn-primary">Validate</button>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</text>
}
</div>
}

}
else
{


<div class="login-form">

@using (Html.BeginUmbracoForm<UmbLoginController>(
"HandleLogin", new { RedirectUrl = loginModel.RedirectUrl })) {

<h4>Log in with a local account.</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="mb-3">
<label asp-for="@loginModel.Username" class="form-label"></label>
<input asp-for="@loginModel.Username" class="form-control" />
<span asp-validation-for="@loginModel.Username" class="form-text text-danger"></span>
</div>
<div class="mb-3">
<label asp-for="@loginModel.Password" class="form-label"></label>
<input asp-for="@loginModel.Password" class="form-control" />
<span asp-validation-for="@loginModel.Password" class="form-text text-danger"></span>
</div>
<div class="mb-3 form-check">
<input asp-for="@loginModel.RememberMe" class="form-check-input">
<label asp-for="@loginModel.RememberMe" class="form-check-label">
@Html.DisplayNameFor(m => loginModel.RememberMe)
</label>
</div>

<button type="submit" class="btn btn-primary">Log in</button>


}
@{
var loginProviders = await memberExternalLoginProviders.GetMemberProvidersAsync();
var externalSignInError = ViewData.GetExternalSignInProviderErrors();

if (loginProviders.Any())
{
<hr/>
<h4>Or using external providers</h4>
if (externalSignInError?.AuthenticationType is null && externalSignInError?.Errors.Any() == true)
{
@Html.DisplayFor(x => externalSignInError.Errors);
}

@foreach (var login in await memberExternalLoginProviders.GetMemberProvidersAsync())
{

@using (Html.BeginUmbracoForm<UmbExternalLoginController>(nameof(UmbExternalLoginController.ExternalLogin)))
{
<button type="submit" name="provider" value="@login.ExternalLoginProvider.AuthenticationType">
Sign in with @login.AuthenticationScheme.DisplayName
</button>

if (externalSignInError?.AuthenticationType == login.ExternalLoginProvider.AuthenticationType)
{
@Html.DisplayFor(x => externalSignInError.Errors);
}
}
}
}
}
</div>
}
Loading

0 comments on commit 0ed255c

Please sign in to comment.