I am making a panel where the website admins can access users' account data and change stuff. For example, name, email, username, etc... I want when the admin changes the email on his computer it will not change the email in the database unless the user confirms it in his new email. I have the registration functions and I kind of used them but with them, I can't change the Email After it clicked, only before. Here's the code, hope you can help me find a way to do this.
[HttpPost]
public async Task<IActionResult> EditUser(EditUserModel model, string returnUrl = null)
{
var user = await userManager.FindByIdAsync(model.Id);
var _user = user;
_user.UserName = model.UserName;
_user.EmailConfirmed = false;
_user.FirstName = model.FirstName;
_user.LastName = model.LastName;
if (user == null)
{
ViewBag.ErrorMessage = $"User with Id: {model.Id} cannot be found";
return View("NotFound");
}
else
{
if (user.Email != model.Email)
{
returnUrl ??= Url.Content("~/");
var result = await userManager.UpdateAsync(_user);
if (result.Succeeded)
{
var code = await userManager.GenerateEmailConfirmationTokenAsync(_user);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
/*
if (NewEmailConfirmed) --> the if statement that supposes to check if the user confirmed his new email
{
_user.Email = model.Email;
await userManager.UpdateAsync(_user);
}
*/
}
}
else //If the admin updated anything but the Email.
{
user.UserName = model.UserName;
user.FirstName = model.FirstName;
user.LastName = model.LastName;
var result = await userManager.UpdateAsync(user);
if (result.Succeeded)
return RedirectToAction("ListUsers");
foreach (var error in result.Errors)
ModelState.AddModelError("", error.Description);
return View(model);
}
}
return RedirectToAction("ListUsers");
}
So, After some research, I found that in the "Add new scaffold item" you can add the checkbox called "Account\Manage\Email". After I added it, when I clicked on my username it opened some user settings and I could change My email. So I took the code from there and after some debugging I found the code below to work 100%.
private UserManager<ApplicationUser> userManager;
private readonly IEmailSender _emailSender;
private readonly ILogger logger;
public AdministrationController(UserManager<ApplicationUser> userManager,
IEmailSender emailSender,
ILogger<AdministrationController> logger)
{
this.userManager = userManager;
_emailSender = emailSender;
this.logger = logger;
}
public string Username { get; set; }
public string Email { get; set; }
public bool IsEmailConfirmed { get; set; }
[TempData]
public string StatusMessage { get; set; }
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[EmailAddress]
[Display(Name = "New email")]
public string NewEmail { get; set; }
}
private async Task LoadAsync(ApplicationUser user)
{
var email = await userManager.GetEmailAsync(user);
Email = email;
Input = new InputModel
{
NewEmail = email,
};
IsEmailConfirmed = await userManager.IsEmailConfirmedAsync(user);
}
public async Task<IActionResult> OnGetAsync()
{
var user = await userManager.GetUserAsync(User);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userManager.GetUserId(User)}'.");
}
await LoadAsync(user);
return RedirectToAction("ListUsers", "Administration");
}
[HttpPost]
public async Task<IActionResult> ChangeEmail(EditUserModel model)
{
var user = await userManager.FindByIdAsync(model.Id);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userManager.GetUserId(User)}'.");
}
//if (!ModelState.IsValid)
//{
// await LoadAsync(user);
// return RedirectToAction("ListUsers", "Administration");
//}
var email = await userManager.GetEmailAsync(user);
if (Input.NewEmail != email && Input.NewEmail != null)
{
var userId = await userManager.GetUserIdAsync(user);
var code = await userManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail);
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
var callbackUrl = Url.Page(
"/Account/ConfirmEmailChange",
pageHandler: null,
values: new { area = "Identity", userId = userId, email = Input.NewEmail, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(
Input.NewEmail,
"Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
StatusMessage = "Confirmation link to change email sent. Please check your email.";
return RedirectToAction("ListUsers", "Administration");
}
StatusMessage = "Your email is unchanged.";
return View(model);
}
[HttpPost]
public async Task<IActionResult> EditUser(EditUserModel model)
{
var user = await userManager.FindByIdAsync(model.Id);
if (user == null)
return NotFound($"User with Id: {model.Id} cannot be found.");
user.UserName = model.UserName;
user.FirstName = model.FirstName;
user.LastName = model.LastName;
var result = await userManager.UpdateAsync(user);
if (result.Succeeded)
{
if (user.Email != Input.NewEmail)
await ChangeEmail(model);
return RedirectToAction("ListUsers");
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
return View(model);
}
public class EditUserModel
{
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[EmailAddress]
[Display(Name = "New email")]
public string NewEmail { get; set; }
}
}
@model SvivaTeamVersion3.Models.EditUserModel
<form method="post">
<div class="form-group row"> @*Display the current Email*@
<label asp-for="Email" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Email" disabled class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group row"> @*Change to a new Email*@
<label asp-for="Input.NewEmail" class="col-sm-2 col-form-label"></label>
<div class="col-sm-10">
<input asp-for="Input.NewEmail" id="newMail" class="form-control" />
</div>
</div>
<div asp-validation-summary="All" class="text-danger"></div>
</form>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
If you have done everything correctly you should have an input box to change the Email. When you change your Email a new Email will be sent to you in your new mail. (only if you have done Email confirmation) If you would click on it the Email will change.