Updates the invite flow, we will always create a local user because we must do that due to the user groups being pre-determined.

This commit is contained in:
Shannon
2020-09-09 18:09:16 +10:00
parent af53f27bc3
commit c7c7d9efcd
5 changed files with 53 additions and 47 deletions

View File

@@ -6,19 +6,16 @@ namespace Umbraco.Core.Models.Identity
{
/// <summary>
/// The login provider for the login (i.e. Facebook, Google)
///
/// </summary>
string LoginProvider { get; set; }
/// <summary>
/// Key representing the login for the provider
///
/// </summary>
string ProviderKey { get; set; }
/// <summary>
/// User Id for the user who owns this login
///
/// </summary>
int UserId { get; set; }
}

View File

@@ -361,38 +361,8 @@ namespace Umbraco.Web.Editors
user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
var userMgr = TryGetOwinContext().Result.GetBackOfficeUserManager();
var inviteArgs = new UserInviteEventArgs(
Request.TryGetHttpContext().Result.GetCurrentRequestIpAddress(),
performingUser: Security.GetUserId().Result,
userSave);
userMgr.RaiseSendingUserInvite(inviteArgs);
// If the event is handled then return the data
if (inviteArgs.InviteHandled)
{
// if no local user was created then map the args manually for the UI
if (inviteArgs.User == null)
{
return new UserDisplay
{
Name = userSave.Name,
Email = userSave.Email,
Username = userSave.Username
};
}
else
{
//map the save info over onto the user
user = Mapper.Map(userSave, user);
//ensure the invited date is set
user.InvitedDate = DateTime.Now;
//Save the updated user
Services.UserService.Save(user);
return Mapper.Map<UserDisplay>(user);
}
}
if (EmailSender.CanSendRequiredEmail == false)
if (!EmailSender.CanSendRequiredEmail && !userMgr.HasSendingUserInviteEventHandler)
{
throw new HttpResponseException(
Request.CreateNotificationValidationErrorResponse("No Email server is configured"));
@@ -430,16 +400,48 @@ namespace Umbraco.Web.Editors
//ensure the invited date is set
user.InvitedDate = DateTime.Now;
//Save the updated user
//Save the updated user (which will process the user groups too)
Services.UserService.Save(user);
var display = Mapper.Map<UserDisplay>(user);
//send the email
var inviteArgs = new UserInviteEventArgs(
Request.TryGetHttpContext().Result.GetCurrentRequestIpAddress(),
performingUser: Security.GetUserId().Result,
userSave,
user);
await SendUserInviteEmailAsync(display, Security.CurrentUser.Name, Security.CurrentUser.Email, user, userSave.Message);
try
{
userMgr.RaiseSendingUserInvite(inviteArgs);
}
catch (Exception ex)
{
Logger.Error<UsersController>(ex, "An error occured in a custom event handler while inviting the user");
throw new HttpResponseException(
Request.CreateNotificationValidationErrorResponse($"An error occured inviting the user (check logs for more info): {ex.Message}"));
}
// If the event is handled then no need to send the email
if (inviteArgs.InviteHandled)
{
// if no user result was created then map the minimum args manually for the UI
if (!inviteArgs.ShowUserResult)
{
display = new UserDisplay
{
Name = userSave.Name,
Email = userSave.Email,
Username = userSave.Username
};
}
}
else
{
//send the email
await SendUserInviteEmailAsync(display, Security.CurrentUser.Name, Security.CurrentUser.Email, user, userSave.Message);
}
display.AddSuccessNotification(Services.TextService.Localize("speechBubbles/resendInviteHeader"), Services.TextService.Localize("speechBubbles/resendInviteSuccess", new[] { user.Name }));
return display;
}

View File

@@ -78,7 +78,7 @@ namespace Umbraco.Web
{
foreach (var error in externalLoginErrors.Errors)
{
sb.AppendFormat(@"errors.push(""{0}"");", error).AppendLine();
sb.AppendFormat(@"errors.push(""{0}"");", error.ToSingleLine()).AppendLine();
}
}

View File

@@ -634,6 +634,7 @@ namespace Umbraco.Web.Security
}
internal void RaiseSendingUserInvite(UserInviteEventArgs args) => OnSendingUserInvite(args);
internal bool HasSendingUserInviteEventHandler => SendingUserInvite != null;
// TODO: Not sure why these are not strongly typed events?? They should be in netcore!
public static event EventHandler AccountLocked;

View File

@@ -5,12 +5,16 @@ namespace Umbraco.Web.Security
{
public class UserInviteEventArgs : IdentityAuditEventArgs
{
public UserInviteEventArgs(string ipAddress, int performingUser, UserInvite invitedUser, string comment = null)
public UserInviteEventArgs(string ipAddress, int performingUser, UserInvite invitedUser, IUser localUser, string comment = null)
: base(AuditEvent.SendingUserInvite, ipAddress, comment, performingUser)
{
InvitedUser = invitedUser ?? throw new System.ArgumentNullException(nameof(invitedUser));
User = localUser;
}
/// <summary>
/// The model used to invite the user
/// </summary>
public UserInvite InvitedUser { get; }
/// <summary>
@@ -19,12 +23,14 @@ namespace Umbraco.Web.Security
public bool InviteHandled { get; set; }
/// <summary>
/// If the event handler has created a local user then this is the result which is used to return the details to the UI
/// The local user that has been created that is pending the invite
/// </summary>
public IUser User { get; }
/// <summary>
/// if set to true will show the edit user button in the UI, else it will not be shown
/// </summary>
/// <remarks>
/// It is optional to create a local user in this event. In many cases the custom invite flow will be for external logins and then local users will
/// be created via the auto-linking process.
/// </remarks>
public IUser User { get; set; }
public bool ShowUserResult { get; set; }
}
}