Allow resending verification email for users (#3726)

* Allow resending verification email for users

Partially address #3645

* Replace RequiresEmailConfirmation with Verified

* Use confirmation modal

Co-authored-by: Dennis Reimann <mail@dennisreimann.de>
This commit is contained in:
Umar Bolatov 2022-05-26 21:36:47 -07:00 committed by GitHub
parent 5dba4a2201
commit a9e08dd587
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 6 deletions

View file

@ -10,10 +10,11 @@ using BTCPayServer.Data;
using BTCPayServer.Events; using BTCPayServer.Events;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.ServerViewModels; using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Storage.Services; using BTCPayServer.Services;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Routing;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
{ {
@ -244,9 +245,6 @@ namespace BTCPayServer.Controllers
return RedirectToAction(nameof(ListUsers)); return RedirectToAction(nameof(ListUsers));
} }
[HttpGet("server/users/{userId}/toggle")] [HttpGet("server/users/{userId}/toggle")]
public async Task<IActionResult> ToggleUser(string userId, bool enable) public async Task<IActionResult> ToggleUser(string userId, bool enable)
{ {
@ -278,6 +276,34 @@ namespace BTCPayServer.Controllers
TempData[WellKnownTempData.SuccessMessage] = $"User {(enable? "enabled": "disabled")}"; TempData[WellKnownTempData.SuccessMessage] = $"User {(enable? "enabled": "disabled")}";
return RedirectToAction(nameof(ListUsers)); return RedirectToAction(nameof(ListUsers));
} }
[HttpGet("server/users/{userId}/verification-email")]
public async Task<IActionResult> SendVerificationEmail(string userId)
{
var user = userId == null ? null : await _UserManager.FindByIdAsync(userId);
if (user == null)
return NotFound();
return View("Confirm", new ConfirmModel("Send verification email", $"This will send a verification email to <strong>{user.Email}</strong>.", "Send"));
}
[HttpPost("server/users/{userId}/verification-email")]
public async Task<IActionResult> SendVerificationEmailPost(string userId)
{
var user = await _UserManager.FindByIdAsync(userId);
if (user == null)
{
throw new ApplicationException($"Unable to load user with ID '{userId}'.");
}
var code = await _UserManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = _linkGenerator.EmailConfirmationLink(user.Id, code, Request.Scheme, Request.Host, Request.PathBase);
(await _emailSenderFactory.GetEmailSender()).SendEmailConfirmation(user.Email, callbackUrl);
TempData[WellKnownTempData.SuccessMessage] = "Verification email sent";
return RedirectToAction(nameof(ListUsers));
}
} }
public class RegisterFromAdminViewModel public class RegisterFromAdminViewModel

View file

@ -7,7 +7,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Mail;
using System.Threading.Tasks; using System.Threading.Tasks;
using BTCPayServer.Abstractions.Constants; using BTCPayServer.Abstractions.Constants;
using BTCPayServer.Abstractions.Extensions; using BTCPayServer.Abstractions.Extensions;
@ -62,6 +61,8 @@ namespace BTCPayServer.Controllers
private readonly StoredFileRepository _StoredFileRepository; private readonly StoredFileRepository _StoredFileRepository;
private readonly FileService _FileService; private readonly FileService _FileService;
private readonly IEnumerable<IStorageProviderService> _StorageProviderServices; private readonly IEnumerable<IStorageProviderService> _StorageProviderServices;
private readonly LinkGenerator _linkGenerator;
private readonly EmailSenderFactory _emailSenderFactory;
public UIServerController( public UIServerController(
UserManager<ApplicationUser> userManager, UserManager<ApplicationUser> userManager,
@ -81,7 +82,10 @@ namespace BTCPayServer.Controllers
CheckConfigurationHostedService sshState, CheckConfigurationHostedService sshState,
EventAggregator eventAggregator, EventAggregator eventAggregator,
IOptions<ExternalServicesOptions> externalServiceOptions, IOptions<ExternalServicesOptions> externalServiceOptions,
Logs logs) Logs logs,
LinkGenerator linkGenerator,
EmailSenderFactory emailSenderFactory
)
{ {
_policiesSettings = policiesSettings; _policiesSettings = policiesSettings;
_Options = options; _Options = options;
@ -101,6 +105,8 @@ namespace BTCPayServer.Controllers
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_externalServiceOptions = externalServiceOptions; _externalServiceOptions = externalServiceOptions;
Logs = logs; Logs = logs;
_linkGenerator = linkGenerator;
_emailSenderFactory = emailSenderFactory;
} }
[Route("server/maintenance")] [Route("server/maintenance")]

View file

@ -95,6 +95,10 @@
} }
</td> </td>
<td class="text-end"> <td class="text-end">
@if (!user.Verified && !user.Disabled) {
<a asp-action="SendVerificationEmail" asp-route-userId="@user.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="This will send a verification email to <strong>@user.Email</strong>.">Resend verification email</a>
<span>-</span>
}
<a asp-action="User" asp-route-userId="@user.Id">Edit</a> <span> - </span> <a asp-action="DeleteUser" asp-route-userId="@user.Id">Remove</a> <a asp-action="User" asp-route-userId="@user.Id">Edit</a> <span> - </span> <a asp-action="DeleteUser" asp-route-userId="@user.Id">Remove</a>
- <a asp-action="ToggleUser" - <a asp-action="ToggleUser"
asp-route-enable="@user.Disabled" asp-route-enable="@user.Disabled"
@ -109,3 +113,5 @@
</div> </div>
<vc:pager view-model="Model"></vc:pager> <vc:pager view-model="Model"></vc:pager>
<partial name="_Confirm" model="@(new ConfirmModel("Send verification email", $"This will send a verification email to the user.", "Send"))" />