Skip to content

Commit

Permalink
Rename Identifier property to usernameOrEmail for clearity (#15814)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored Apr 23, 2024
1 parent 526bbc0 commit aa3f069
Show file tree
Hide file tree
Showing 15 changed files with 41 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ private async Task<SignInResult> ExternalLoginSignInAsync(IUser user, ExternalLo
}
catch (Exception ex)
{
_logger.LogError(ex, "{externalLoginHandler} - IExternalLoginHandler.UpdateRoles threw an exception", item.GetType());
_logger.LogError(ex, "{ExternalLoginHandler}.UpdateRoles threw an exception", item.GetType());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,15 @@ public async Task<IActionResult> EditPassword(string id)
return Forbid();
}

var model = new ResetPasswordViewModel { Identifier = user.UserName };
var model = new ResetPasswordViewModel { UsernameOrEmail = user.UserName };

return View(model);
}

[HttpPost]
public async Task<IActionResult> EditPassword(ResetPasswordViewModel model)
{
if (await _userService.GetUserAsync(model.Identifier) is not User user)
if (await _userService.GetUserAsync(model.UsernameOrEmail) is not User user)
{
return NotFound();
}
Expand All @@ -521,7 +521,7 @@ public async Task<IActionResult> EditPassword(ResetPasswordViewModel model)
{
var token = await _userManager.GeneratePasswordResetTokenAsync(user);

if (await _userService.ResetPasswordAsync(model.Identifier, token, model.NewPassword, ModelState.AddModelError))
if (await _userService.ResetPasswordAsync(model.UsernameOrEmail, token, model.NewPassword, ModelState.AddModelError))
{
await _notifier.SuccessAsync(H["Password updated correctly."]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public async Task<IActionResult> ForgotPasswordPOST()

if (ModelState.IsValid)
{
var user = await _userService.GetForgotPasswordUserAsync(model.Identifier) as User;
var user = await _userService.GetForgotPasswordUserAsync(model.UsernameOrEmail) as User;
if (user == null || await MustValidateEmailAsync(user))
{
// returns to confirmation page anyway: we don't want to let scrapers know if a username or an email exist
Expand Down Expand Up @@ -166,7 +166,7 @@ public async Task<IActionResult> ResetPasswordPOST()
{
var token = Encoding.UTF8.GetString(Convert.FromBase64String(model.ResetToken));

if (await _userService.ResetPasswordAsync(model.Identifier, token, model.NewPassword, ModelState.AddModelError))
if (await _userService.ResetPasswordAsync(model.UsernameOrEmail, token, model.NewPassword, ModelState.AddModelError))
{
return RedirectToAction(nameof(ResetPasswordConfirmation));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public override IDisplayResult Edit(ForgotPasswordForm model)
{
return Initialize<ForgotPasswordViewModel>("ForgotPasswordFormIdentifier", vm =>
{
vm.Identifier = model.Identifier;
vm.UsernameOrEmail = model.UsernameOrEmail;
}).Location("Content");
}

Expand All @@ -23,7 +23,7 @@ public override async Task<IDisplayResult> UpdateAsync(ForgotPasswordForm model,

await updater.TryUpdateModelAsync(viewModel, Prefix);

model.Identifier = viewModel.Identifier;
model.UsernameOrEmail = viewModel.UsernameOrEmail;

return Edit(model);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public override IDisplayResult Edit(ResetPasswordForm model)
{
return Initialize<ResetPasswordViewModel>("ResetPasswordFormIdentifier", vm =>
{
vm.Identifier = model.Identifier;
vm.UsernameOrEmail = model.UsernameOrEmail;
vm.NewPassword = model.NewPassword;
vm.ResetToken = model.ResetToken;
}).Location("Content");
Expand All @@ -25,7 +25,7 @@ public override async Task<IDisplayResult> UpdateAsync(ResetPasswordForm model,

await updater.TryUpdateModelAsync(vm, Prefix);

model.Identifier = vm.Identifier;
model.UsernameOrEmail = vm.UsernameOrEmail;
model.NewPassword = vm.NewPassword;
model.ResetToken = vm.ResetToken;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ namespace OrchardCore.Users.ViewModels
{
public class ForgotPasswordViewModel
{
[Obsolete("Email property is no longer used and will be removed in future releases. Instead use Identifier.")]
[Obsolete("Email property is no longer used and will be removed in future releases. Instead use UsernameOrEmail.")]
[Email.EmailAddress(ErrorMessage = "Invalid Email.")]
public string Email { get; set; }

[Required(ErrorMessage = "Username or email address is required.")]
public string Identifier { get; set; }
public string UsernameOrEmail { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ namespace OrchardCore.Users.ViewModels
{
public class ResetPasswordViewModel
{
[Obsolete("Email property is no longer used and will be removed in future releases. Instead use Identifier.")]
[Obsolete("Email property is no longer used and will be removed in future releases. Instead use UsernameOrEmail.")]
[Email.EmailAddress(ErrorMessage = "Invalid Email.")]
public string Email { get; set; }

[Required(ErrorMessage = "Username or email address is required.")]
public string Identifier { get; set; }
public string UsernameOrEmail { get; set; }

[Required(ErrorMessage = "New password is required.")]
[DataType(DataType.Password)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<form asp-controller="Admin" asp-action="EditPassword" method="post" class="form-horizontal no-multisubmit">
<div asp-validation-summary="All"></div>
<input asp-for="Identifier" type="hidden" />
<input asp-for="UsernameOrEmail" type="hidden" />
<div class="mb-3">
<label asp-for="NewPassword" class="w-lg-75 w-xl-50 form-label">@T["New password"]</label>
<div class="w-lg-75 w-xl-50">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@model ForgotPasswordViewModel

<div class="mb-3">
<label asp-for="Identifier" class="form-label">@T["Username or email address"]</label>
<input asp-for="Identifier" class="form-control" />
<label asp-for="UsernameOrEmail" class="form-label">@T["Username or email address"]</label>
<input asp-for="UsernameOrEmail" class="form-control" />
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
<input asp-for="ResetToken" type="hidden" />

<div class="mb-3">
<label asp-for="Identifier" class="form-label">@T["Username or email address"]</label>
<input asp-for="Identifier" class="form-control" />
<span asp-validation-for="Identifier" class="text-danger"></span>
<label asp-for="UsernameOrEmail" class="form-label">@T["Username or email address"]</label>
<input asp-for="UsernameOrEmail" class="form-control" />
<span asp-validation-for="UsernameOrEmail" class="text-danger"></span>
</div>

<div class="mb-3">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public interface IUserService
/// <summary>
/// Authenticates the user credentials.
/// </summary>
/// <param name="identifier">The username or email address.</param>
/// <param name="usernameOrEmail">The username or email address.</param>
/// <param name="password">The user password.</param>
/// <param name="reportError">The error reported in case failure happened during the authentication process.</param>
/// <returns>A <see cref="IUser"/> that represents an authenticated user.</returns>
Task<IUser> AuthenticateAsync(string identifier, string password, Action<string, string> reportError);
Task<IUser> AuthenticateAsync(string usernameOrEmail, string password, Action<string, string> reportError);

/// <summary>
/// Creates a user.
Expand Down Expand Up @@ -56,9 +56,9 @@ public interface IUserService
/// <summary>
/// Gets the user with a specified username or email address.
/// </summary>
/// <param name="identifier">The username or email address.</param>
/// <param name="usernameOrEmail">The username or email address.</param>
/// <returns>The <see cref="IUser"/> represents the retrieved user.</returns>
Task<IUser> GetUserAsync(string identifier);
Task<IUser> GetUserAsync(string usernameOrEmail);

/// <summary>
/// Gets the user with a specified ID.
Expand All @@ -77,12 +77,12 @@ public interface IUserService
/// <summary>
/// Resets the user password.
/// </summary>
/// <param name="identifier">The username or email address.</param>
/// <param name="usernameOrEmail">The username or email address.</param>
/// <param name="resetToken">The token used to reset the password.</param>
/// <param name="newPassword">The new password.</param>
/// <param name="reportError">The error reported in case failure happened during the reset process.</param>
/// <returns>Returns <c>true</c> if the password reset, otherwise <c>false</c>.</returns>
Task<bool> ResetPasswordAsync(string identifier, string resetToken, string newPassword, Action<string, string> reportError);
Task<bool> ResetPasswordAsync(string usernameOrEmail, string resetToken, string newPassword, Action<string, string> reportError);

/// <summary>
/// Creates a <see cref="ClaimsPrincipal"/> for a given user.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ namespace OrchardCore.Users.Models;

public class ForgotPasswordForm : Entity
{
public string Identifier { get; set; }
public string UsernameOrEmail { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace OrchardCore.Users.Models;

public class ResetPasswordForm : Entity
{
public string Identifier { get; set; }
public string UsernameOrEmail { get; set; }

public string NewPassword { get; set; }

Expand Down
23 changes: 12 additions & 11 deletions src/OrchardCore/OrchardCore.Users.Core/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public UserService(
_logger = logger;
}

public async Task<IUser> AuthenticateAsync(string identifier, string password, Action<string, string> reportError)
public async Task<IUser> AuthenticateAsync(string usernameOrEmail, string password, Action<string, string> reportError)
{
var disableLocalLogin = (await _siteService.GetSiteSettingsAsync()).As<LoginSettings>().DisableLocalLogin;

Expand All @@ -55,7 +55,7 @@ public async Task<IUser> AuthenticateAsync(string identifier, string password, A
return null;
}

if (string.IsNullOrWhiteSpace(identifier))
if (string.IsNullOrWhiteSpace(usernameOrEmail))
{
reportError("Username", S["A user name is required."]);
return null;
Expand All @@ -67,7 +67,7 @@ public async Task<IUser> AuthenticateAsync(string identifier, string password, A
return null;
}

var user = await GetUserAsync(identifier);
var user = await GetUserAsync(usernameOrEmail);
if (user == null)
{
reportError(string.Empty, S["The specified username/password couple is invalid."]);
Expand Down Expand Up @@ -184,12 +184,12 @@ public async Task<IUser> GetForgotPasswordUserAsync(string userId)
return user;
}

public async Task<bool> ResetPasswordAsync(string identifier, string resetToken, string newPassword, Action<string, string> reportError)
public async Task<bool> ResetPasswordAsync(string usernameOrEmail, string resetToken, string newPassword, Action<string, string> reportError)
{
var result = true;
if (string.IsNullOrWhiteSpace(identifier))
if (string.IsNullOrWhiteSpace(usernameOrEmail))
{
reportError(nameof(ResetPasswordForm.Identifier), S["A username or email address is required."]);
reportError(nameof(ResetPasswordForm.UsernameOrEmail), S["A username or email address is required."]);
result = false;
}

Expand All @@ -210,7 +210,7 @@ public async Task<bool> ResetPasswordAsync(string identifier, string resetToken,
return result;
}

var user = await GetUserAsync(identifier) as User;
var user = await GetUserAsync(usernameOrEmail) as User;

if (user == null)
{
Expand Down Expand Up @@ -244,19 +244,20 @@ public Task<ClaimsPrincipal> CreatePrincipalAsync(IUser user)
return _signInManager.CreateUserPrincipalAsync(user);
}

public async Task<IUser> GetUserAsync(string identifier)
public async Task<IUser> GetUserAsync(string usernameOrEmail)
{
var user = await _userManager.FindByNameAsync(identifier);
var user = await _userManager.FindByNameAsync(usernameOrEmail);

if (user is null && _identityOptions.User.RequireUniqueEmail)
{
user = await _userManager.FindByEmailAsync(identifier);
user = await _userManager.FindByEmailAsync(usernameOrEmail);
}

return user;
}

public Task<IUser> GetUserByUniqueIdAsync(string userIdentifier) => _userManager.FindByIdAsync(userIdentifier);
public Task<IUser> GetUserByUniqueIdAsync(string userId)
=> _userManager.FindByIdAsync(userId);

public void ProcessValidationErrors(IEnumerable<IdentityError> errors, User user, Action<string, string> reportError)
{
Expand Down
2 changes: 1 addition & 1 deletion src/docs/releases/1.9.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public class ReCaptchaResetPasswordFormDisplayDriver : DisplayDriver<ResetPasswo
}
```

Previously, users were only able to reset their password through email when the "Reset Password" feature was enabled. However, we've enhanced this functionality to offer users the flexibility of resetting their password using either their email or username. Consequently, the `Email` property on both the `ForgotPasswordViewModel` and `ResetPasswordViewModel` have been deprecated and should be replaced with the new Identifier property for password resets.
Previously, users were only able to reset their password through email when the "Reset Password" feature was enabled. However, we've enhanced this functionality to offer users the flexibility of resetting their password using either their email or username. Consequently, the `Email` property on both the `ForgotPasswordViewModel` and `ResetPasswordViewModel` have been deprecated and should be replaced with the new `UsernameOrEmail` property for password resets.

- The `Register.cshtml` has undergone a significant revamp. The previous `AfterRegister` zone, which allowed filters for injecting shapes, has been replaced. Now, you can inject shapes using drivers by implementing `IDisplayDriver<RegisterUserForm>`. For example, the ReCaptcha shape is injected using the following driver:

Expand Down

0 comments on commit aa3f069

Please sign in to comment.