2020-09-05 12:16:48 +02:00
using System ;
using System.ComponentModel.DataAnnotations ;
using System.Linq ;
using System.Threading.Tasks ;
2022-02-21 15:46:43 +01:00
using BTCPayServer.Abstractions.Constants ;
2020-11-17 13:46:23 +01:00
using BTCPayServer.Abstractions.Extensions ;
using BTCPayServer.Abstractions.Models ;
2020-09-05 12:16:48 +02:00
using BTCPayServer.Data ;
using BTCPayServer.Events ;
using BTCPayServer.Models.ServerViewModels ;
2022-05-26 21:36:47 -07:00
using BTCPayServer.Services ;
2024-02-28 12:43:18 +01:00
using BTCPayServer.Services.Mails ;
2020-09-05 12:16:48 +02:00
using Microsoft.AspNetCore.Identity ;
using Microsoft.AspNetCore.Mvc ;
2023-01-06 14:18:07 +01:00
using Microsoft.EntityFrameworkCore ;
2020-09-05 12:16:48 +02:00
namespace BTCPayServer.Controllers
{
2022-01-07 12:32:00 +09:00
public partial class UIServerController
2020-09-05 12:16:48 +02:00
{
2024-01-31 06:45:54 +01:00
[HttpGet("server/users")]
2021-03-29 22:32:44 -07:00
public async Task < IActionResult > ListUsers (
2021-11-15 10:27:19 +01:00
[FromServices] RoleManager < IdentityRole > roleManager ,
2024-01-31 06:45:54 +01:00
UsersViewModel model ,
string sortOrder = null )
2020-09-05 12:16:48 +02:00
{
2020-10-03 14:12:55 +02:00
model = this . ParseListQuery ( model ? ? new UsersViewModel ( ) ) ;
2021-12-31 16:59:02 +09:00
2021-03-29 22:32:44 -07:00
var usersQuery = _UserManager . Users ;
if ( ! string . IsNullOrWhiteSpace ( model . SearchTerm ) )
{
2021-04-13 17:06:11 +09:00
#pragma warning disable CA1307 // Specify StringComparison
// Entity Framework don't support StringComparison
2021-03-29 22:32:44 -07:00
usersQuery = usersQuery . Where ( u = > u . Email . Contains ( model . SearchTerm ) ) ;
2021-04-13 17:06:11 +09:00
#pragma warning restore CA1307 // Specify StringComparison
2021-03-29 22:32:44 -07:00
}
2021-12-31 16:59:02 +09:00
if ( sortOrder ! = null )
2021-03-29 22:32:44 -07:00
{
switch ( sortOrder )
{
case "desc" :
ViewData [ "NextUserEmailSortOrder" ] = "asc" ;
usersQuery = usersQuery . OrderByDescending ( user = > user . Email ) ;
break ;
case "asc" :
usersQuery = usersQuery . OrderBy ( user = > user . Email ) ;
ViewData [ "NextUserEmailSortOrder" ] = "desc" ;
break ;
}
}
2021-11-15 10:27:19 +01:00
model . Roles = roleManager . Roles . ToDictionary ( role = > role . Id , role = > role . Name ) ;
2024-06-26 10:39:22 +02:00
model . Users = ( await usersQuery
2021-11-15 10:27:19 +01:00
. Include ( user = > user . UserRoles )
2024-02-23 09:51:41 +01:00
. Include ( user = > user . UserStores )
. ThenInclude ( data = > data . StoreData )
2021-03-29 22:32:44 -07:00
. Skip ( model . Skip )
. Take ( model . Count )
2024-06-26 10:39:22 +02:00
. ToListAsync ( ) )
2024-09-12 05:31:57 +02:00
. Select ( u = >
2020-09-05 12:16:48 +02:00
{
2024-09-12 05:31:57 +02:00
var blob = u . GetBlob ( ) ;
return new UsersViewModel . UserViewModel
{
Name = blob ? . Name ,
ImageUrl = blob ? . ImageUrl ,
Email = u . Email ,
Id = u . Id ,
InvitationUrl =
string . IsNullOrEmpty ( blob ? . InvitationToken )
? null
: _linkGenerator . InvitationLink ( u . Id , blob . InvitationToken , Request . Scheme ,
Request . Host , Request . PathBase ) ,
EmailConfirmed = u . RequiresEmailConfirmation ? u . EmailConfirmed : null ,
Approved = u . RequiresApproval ? u . Approved : null ,
Created = u . Created ,
Roles = u . UserRoles . Select ( role = > role . RoleId ) ,
Disabled = u . LockoutEnabled & & u . LockoutEnd ! = null & &
DateTimeOffset . UtcNow < u . LockoutEnd . Value . UtcDateTime ,
Stores = u . UserStores . OrderBy ( s = > ! s . StoreData . Archived ) . ToList ( )
} ;
2021-03-29 22:32:44 -07:00
} )
2024-06-26 10:39:22 +02:00
. ToList ( ) ;
2020-10-03 14:12:55 +02:00
return View ( model ) ;
2020-09-05 12:16:48 +02:00
}
2024-01-31 06:45:54 +01:00
[HttpGet("server/users/{userId}")]
2020-09-05 12:16:48 +02:00
public new async Task < IActionResult > User ( string userId )
{
var user = await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
var roles = await _UserManager . GetRolesAsync ( user ) ;
2024-06-26 10:39:22 +02:00
var blob = user . GetBlob ( ) ;
2024-01-31 06:45:54 +01:00
var model = new UsersViewModel . UserViewModel
2020-10-03 14:12:55 +02:00
{
Id = user . Id ,
Email = user . Email ,
2024-06-26 10:39:22 +02:00
Name = blob ? . Name ,
2024-09-12 05:31:57 +02:00
InvitationUrl = string . IsNullOrEmpty ( blob ? . InvitationToken ) ? null : _linkGenerator . InvitationLink ( user . Id , blob . InvitationToken , Request . Scheme , Request . Host , Request . PathBase ) ,
2024-06-26 10:39:22 +02:00
ImageUrl = string . IsNullOrEmpty ( blob ? . ImageUrl ) ? null : await _uriResolver . Resolve ( Request . GetAbsoluteRootUri ( ) , UnresolvedUri . Create ( blob . ImageUrl ) ) ,
2024-01-31 06:45:54 +01:00
EmailConfirmed = user . RequiresEmailConfirmation ? user . EmailConfirmed : null ,
Approved = user . RequiresApproval ? user . Approved : null ,
2023-02-15 14:28:34 +09:00
IsAdmin = Roles . HasServerAdmin ( roles )
2020-10-03 14:12:55 +02:00
} ;
2024-01-31 06:45:54 +01:00
return View ( model ) ;
2020-09-05 12:16:48 +02:00
}
2024-01-31 06:45:54 +01:00
[HttpPost("server/users/{userId}")]
2024-06-26 10:39:22 +02:00
public new async Task < IActionResult > User ( string userId , UsersViewModel . UserViewModel viewModel , [ FromForm ] bool RemoveImageFile = false )
2020-09-05 12:16:48 +02:00
{
var user = await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
2024-01-31 06:45:54 +01:00
bool? propertiesChanged = null ;
bool? adminStatusChanged = null ;
bool? approvalStatusChanged = null ;
2024-02-28 12:43:18 +01:00
if ( user . RequiresApproval & & viewModel . Approved . HasValue & & user . Approved ! = viewModel . Approved . Value )
2024-01-31 06:45:54 +01:00
{
approvalStatusChanged = await _userService . SetUserApproval ( user . Id , viewModel . Approved . Value , Request . GetAbsoluteRootUri ( ) ) ;
}
if ( user . RequiresEmailConfirmation & & viewModel . EmailConfirmed . HasValue & & user . EmailConfirmed ! = viewModel . EmailConfirmed )
{
user . EmailConfirmed = viewModel . EmailConfirmed . Value ;
propertiesChanged = true ;
}
2024-06-26 10:39:22 +02:00
var blob = user . GetBlob ( ) ? ? new ( ) ;
if ( blob . Name ! = viewModel . Name )
{
blob . Name = viewModel . Name ;
propertiesChanged = true ;
}
2024-11-07 02:43:22 +01:00
2024-06-26 10:39:22 +02:00
if ( viewModel . ImageFile ! = null )
{
2024-11-07 02:43:22 +01:00
var imageUpload = await _fileService . UploadImage ( viewModel . ImageFile , user . Id ) ;
if ( ! imageUpload . Success )
ModelState . AddModelError ( nameof ( viewModel . ImageFile ) , imageUpload . Response ) ;
2024-06-26 10:39:22 +02:00
else
{
2024-11-07 02:43:22 +01:00
try
2024-06-26 10:39:22 +02:00
{
2024-11-07 02:43:22 +01:00
var storedFile = imageUpload . StoredFile ! ;
var fileIdUri = new UnresolvedUri . FileIdUri ( storedFile . Id ) ;
blob . ImageUrl = fileIdUri . ToString ( ) ;
propertiesChanged = true ;
2024-06-26 10:39:22 +02:00
}
2024-11-07 02:43:22 +01:00
catch ( Exception e )
2024-06-26 10:39:22 +02:00
{
2024-11-07 02:43:22 +01:00
ModelState . AddModelError ( nameof ( viewModel . ImageFile ) , StringLocalizer [ "Could not save image: {0}" , e . Message ] ) ;
2024-06-26 10:39:22 +02:00
}
}
}
else if ( RemoveImageFile & & ! string . IsNullOrEmpty ( blob . ImageUrl ) )
{
blob . ImageUrl = null ;
propertiesChanged = true ;
}
user . SetBlob ( blob ) ;
2020-09-05 12:16:48 +02:00
var admins = await _UserManager . GetUsersInRoleAsync ( Roles . ServerAdmin ) ;
var roles = await _UserManager . GetRolesAsync ( user ) ;
2023-02-15 14:28:34 +09:00
var wasAdmin = Roles . HasServerAdmin ( roles ) ;
2020-09-05 12:16:48 +02:00
if ( ! viewModel . IsAdmin & & admins . Count = = 1 & & wasAdmin )
{
2024-11-07 02:43:22 +01:00
TempData [ WellKnownTempData . ErrorMessage ] = StringLocalizer [ "This is the only admin, so their role can't be removed until another admin is added." ] . Value ;
2024-01-31 06:45:54 +01:00
return View ( viewModel ) ;
2020-09-05 12:16:48 +02:00
}
if ( viewModel . IsAdmin ! = wasAdmin )
{
2024-01-31 06:45:54 +01:00
adminStatusChanged = await _userService . SetAdminUser ( user . Id , viewModel . IsAdmin ) ;
}
if ( propertiesChanged is true )
{
propertiesChanged = await _UserManager . UpdateAsync ( user ) is { Succeeded : true } ;
}
if ( propertiesChanged . HasValue | | adminStatusChanged . HasValue | | approvalStatusChanged . HasValue )
{
if ( propertiesChanged is not false & & adminStatusChanged is not false & & approvalStatusChanged is not false )
2022-06-06 18:42:59 -07:00
{
2024-10-17 15:51:40 +02:00
TempData [ WellKnownTempData . SuccessMessage ] = StringLocalizer [ "User successfully updated" ] . Value ;
2022-06-06 18:42:59 -07:00
}
2020-09-05 12:16:48 +02:00
else
2022-06-06 18:42:59 -07:00
{
2024-10-17 15:51:40 +02:00
TempData [ WellKnownTempData . ErrorMessage ] = StringLocalizer [ "Error updating user" ] . Value ;
2022-06-06 18:42:59 -07:00
}
2020-09-05 12:16:48 +02:00
}
2024-01-31 06:45:54 +01:00
return RedirectToAction ( nameof ( User ) , new { userId } ) ;
2020-09-05 12:16:48 +02:00
}
2024-09-13 13:42:08 +01:00
[HttpGet("server/users/{userId}/reset-password")]
public async Task < IActionResult > ResetUserPassword ( string userId )
{
var user = await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
return View ( new ResetUserPasswordFromAdmin { Email = user . Email } ) ;
}
[HttpPost("server/users/{userId}/reset-password")]
public async Task < IActionResult > ResetUserPassword ( string userId , ResetUserPasswordFromAdmin model )
{
var user = await _UserManager . FindByEmailAsync ( model . Email ) ;
if ( user = = null | | user . Id ! = userId )
return NotFound ( ) ;
var result = await _UserManager . ResetPasswordAsync ( user , await _UserManager . GeneratePasswordResetTokenAsync ( user ) , model . Password ) ;
TempData . SetStatusMessageModel ( new StatusMessageModel
{
Severity = result . Succeeded ? StatusMessageModel . StatusSeverity . Success : StatusMessageModel . StatusSeverity . Error ,
2024-10-17 15:51:40 +02:00
Message = result . Succeeded ? StringLocalizer [ "Password successfully set" ] . Value : StringLocalizer [ "An error occurred while resetting user password" ] . Value
2024-09-13 13:42:08 +01:00
} ) ;
return RedirectToAction ( nameof ( ListUsers ) ) ;
}
2024-01-31 06:45:54 +01:00
[HttpGet("server/users/new")]
2024-09-12 05:31:57 +02:00
public async Task < IActionResult > CreateUser ( )
2020-09-05 12:16:48 +02:00
{
2024-09-12 05:31:57 +02:00
await PrepareCreateUserViewData ( ) ;
var vm = new RegisterFromAdminViewModel
{
SendInvitationEmail = ViewData [ "CanSendEmail" ] is true
} ;
return View ( vm ) ;
2020-09-05 12:16:48 +02:00
}
2024-01-31 06:45:54 +01:00
[HttpPost("server/users/new")]
2020-09-05 12:16:48 +02:00
public async Task < IActionResult > CreateUser ( RegisterFromAdminViewModel model )
{
2024-09-12 05:31:57 +02:00
await PrepareCreateUserViewData ( ) ;
2021-10-11 12:32:09 +09:00
if ( ! _Options . CheatMode )
2020-10-08 11:56:58 +09:00
model . IsAdmin = false ;
2020-09-05 12:16:48 +02:00
if ( ModelState . IsValid )
{
2021-12-31 16:59:02 +09:00
var user = new ApplicationUser
{
UserName = model . Email ,
Email = model . Email ,
EmailConfirmed = model . EmailConfirmed ,
2024-01-31 06:45:54 +01:00
RequiresEmailConfirmation = _policiesSettings . RequiresConfirmedEmail ,
RequiresApproval = _policiesSettings . RequiresUserApproval ,
2024-02-28 12:43:18 +01:00
Approved = true , // auto-approve users created by an admin
2021-12-31 16:59:02 +09:00
Created = DateTimeOffset . UtcNow
} ;
2020-09-05 12:16:48 +02:00
2024-02-28 12:43:18 +01:00
var result = string . IsNullOrEmpty ( model . Password )
? await _UserManager . CreateAsync ( user )
: await _UserManager . CreateAsync ( user , model . Password ) ;
2021-12-31 16:59:02 +09:00
2020-09-05 12:16:48 +02:00
if ( result . Succeeded )
{
if ( model . IsAdmin & & ! ( await _UserManager . AddToRoleAsync ( user , Roles . ServerAdmin ) ) . Succeeded )
model . IsAdmin = false ;
var tcs = new TaskCompletionSource < Uri > ( ) ;
2024-02-28 12:43:18 +01:00
var currentUser = await _UserManager . GetUserAsync ( HttpContext . User ) ;
2024-09-12 05:31:57 +02:00
var sendEmail = model . SendInvitationEmail & & ViewData [ "CanSendEmail" ] is true ;
2021-12-31 16:59:02 +09:00
2024-02-28 12:43:18 +01:00
_eventAggregator . Publish ( new UserRegisteredEvent
2020-09-05 12:16:48 +02:00
{
2021-12-31 16:59:02 +09:00
RequestUri = Request . GetAbsoluteRootUri ( ) ,
2024-03-19 14:58:33 +01:00
Kind = UserRegisteredEventKind . Invite ,
2021-12-31 16:59:02 +09:00
User = user ,
2024-02-28 12:43:18 +01:00
InvitedByUser = currentUser ,
2024-09-12 05:31:57 +02:00
SendInvitationEmail = sendEmail ,
2024-02-28 12:43:18 +01:00
Admin = model . IsAdmin ,
2021-12-31 16:59:02 +09:00
CallbackUrlGenerated = tcs
2020-09-05 12:16:48 +02:00
} ) ;
2024-02-28 12:43:18 +01:00
2020-09-05 12:16:48 +02:00
var callbackUrl = await tcs . Task ;
2024-09-12 05:31:57 +02:00
var info = sendEmail
? "An invitation email has been sent. You may alternatively"
: "An invitation email has not been sent. You need to" ;
2024-02-28 12:43:18 +01:00
TempData . SetStatusMessageModel ( new StatusMessageModel
2020-09-05 12:16:48 +02:00
{
2024-02-28 12:43:18 +01:00
Severity = StatusMessageModel . StatusSeverity . Success ,
AllowDismiss = false ,
2024-09-12 05:31:57 +02:00
Html = $"Account successfully created. {info} share this link with them:<br/>{callbackUrl}"
2024-02-28 12:43:18 +01:00
} ) ;
2024-09-12 05:31:57 +02:00
return RedirectToAction ( nameof ( User ) , new { userId = user . Id } ) ;
2020-09-05 12:16:48 +02:00
}
2021-12-31 16:59:02 +09:00
2020-09-05 12:16:48 +02:00
foreach ( var error in result . Errors )
{
ModelState . AddModelError ( string . Empty , error . Description ) ;
}
}
// If we got this far, something failed, redisplay form
return View ( model ) ;
}
2021-09-07 04:55:53 +02:00
[HttpGet("server/users/{userId}/delete")]
2020-09-05 12:16:48 +02:00
public async Task < IActionResult > DeleteUser ( string userId )
{
var user = userId = = null ? null : await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
var roles = await _UserManager . GetRolesAsync ( user ) ;
2023-02-15 14:28:34 +09:00
if ( Roles . HasServerAdmin ( roles ) )
2020-09-05 12:16:48 +02:00
{
2022-04-26 14:27:35 +02:00
if ( await _userService . IsUserTheOnlyOneAdmin ( user ) )
2020-09-05 12:16:48 +02:00
{
2024-10-17 15:51:40 +02:00
return View ( "Confirm" , new ConfirmModel ( StringLocalizer [ "Delete admin" ] ,
2023-01-22 03:08:12 +09:00
$"Unable to proceed: As the user <strong>{Html.Encode(user.Email)}</strong> is the last enabled admin, it cannot be removed." ) ) ;
2020-09-05 12:16:48 +02:00
}
2024-10-17 15:51:40 +02:00
return View ( "Confirm" , new ConfirmModel ( StringLocalizer [ "Delete admin" ] ,
2024-10-25 15:48:53 +02:00
StringLocalizer [ "The admin {0} will be permanently deleted. This action will also delete all accounts, users and data associated with the server account. Are you sure?" , Html . Encode ( user . Email ) ] ,
StringLocalizer [ "Delete" ] ) ) ;
2020-09-05 12:16:48 +02:00
}
2021-12-31 16:59:02 +09:00
2024-10-17 15:51:40 +02:00
return View ( "Confirm" , new ConfirmModel ( StringLocalizer [ "Delete user" ] , $"The user <strong>{Html.Encode(user.Email)}</strong> will be permanently deleted. Are you sure?" , "Delete" ) ) ;
2020-09-05 12:16:48 +02:00
}
2021-09-07 04:55:53 +02:00
[HttpPost("server/users/{userId}/delete")]
2020-09-05 12:16:48 +02:00
public async Task < IActionResult > DeleteUserPost ( string userId )
{
var user = userId = = null ? null : await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
2021-03-14 12:24:32 -07:00
await _userService . DeleteUserAndAssociatedData ( user ) ;
2020-09-05 12:16:48 +02:00
2024-10-17 15:51:40 +02:00
TempData [ WellKnownTempData . SuccessMessage ] = StringLocalizer [ "User deleted" ] . Value ;
2020-09-05 12:16:48 +02:00
return RedirectToAction ( nameof ( ListUsers ) ) ;
}
2022-04-26 14:27:35 +02:00
[HttpGet("server/users/{userId}/toggle")]
public async Task < IActionResult > ToggleUser ( string userId , bool enable )
{
var user = userId = = null ? null : await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
if ( ! enable & & await _userService . IsUserTheOnlyOneAdmin ( user ) )
{
2024-10-17 15:51:40 +02:00
return View ( "Confirm" , new ConfirmModel ( StringLocalizer [ "Disable admin" ] ,
2023-01-22 03:08:12 +09:00
$"Unable to proceed: As the user <strong>{Html.Encode(user.Email)}</strong> is the last enabled admin, it cannot be disabled." ) ) ;
2022-04-26 14:27:35 +02:00
}
2023-01-22 03:08:12 +09:00
return View ( "Confirm" , new ConfirmModel ( $"{(enable ? " Enable " : " Disable ")} user" , $"The user <strong>{Html.Encode(user.Email)}</strong> will be {(enable ? " enabled " : " disabled ")}. Are you sure?" , ( enable ? "Enable" : "Disable" ) ) ) ;
2022-04-26 14:27:35 +02:00
}
2023-01-06 14:18:07 +01:00
2022-04-26 14:27:35 +02:00
[HttpPost("server/users/{userId}/toggle")]
public async Task < IActionResult > ToggleUserPost ( string userId , bool enable )
{
var user = userId = = null ? null : await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
if ( ! enable & & await _userService . IsUserTheOnlyOneAdmin ( user ) )
{
2024-10-17 15:51:40 +02:00
TempData [ WellKnownTempData . SuccessMessage ] = StringLocalizer [ "User was the last enabled admin and could not be disabled." ] . Value ;
2022-04-26 14:27:35 +02:00
return RedirectToAction ( nameof ( ListUsers ) ) ;
}
2023-01-06 14:18:07 +01:00
await _userService . ToggleUser ( userId , enable ? null : DateTimeOffset . MaxValue ) ;
2022-04-26 14:27:35 +02:00
2024-10-17 15:51:40 +02:00
TempData [ WellKnownTempData . SuccessMessage ] = enable
? StringLocalizer [ "User enabled" ] . Value
: StringLocalizer [ "User disabled" ] . Value ;
2022-04-26 14:27:35 +02:00
return RedirectToAction ( nameof ( ListUsers ) ) ;
}
2022-05-26 21:36:47 -07:00
2024-01-31 06:45:54 +01:00
[HttpGet("server/users/{userId}/approve")]
public async Task < IActionResult > ApproveUser ( string userId , bool approved )
{
var user = userId = = null ? null : await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
return View ( "Confirm" , new ConfirmModel ( $"{(approved ? " Approve " : " Unapprove ")} user" , $"The user <strong>{Html.Encode(user.Email)}</strong> will be {(approved ? " approved " : " unapproved ")}. Are you sure?" , ( approved ? "Approve" : "Unapprove" ) ) ) ;
}
[HttpPost("server/users/{userId}/approve")]
public async Task < IActionResult > ApproveUserPost ( string userId , bool approved )
{
var user = userId = = null ? null : await _UserManager . FindByIdAsync ( userId ) ;
if ( user = = null )
return NotFound ( ) ;
await _userService . SetUserApproval ( userId , approved , Request . GetAbsoluteRootUri ( ) ) ;
2024-10-17 15:51:40 +02:00
TempData [ WellKnownTempData . SuccessMessage ] = approved
? StringLocalizer [ "User approved" ] . Value
: StringLocalizer [ "User unapproved" ] . Value ;
2024-01-31 06:45:54 +01:00
return RedirectToAction ( nameof ( ListUsers ) ) ;
}
2022-05-26 21:36:47 -07:00
[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 ( ) ;
2023-01-06 14:18:07 +01:00
2024-10-17 15:51:40 +02:00
return View ( "Confirm" , new ConfirmModel ( StringLocalizer [ "Send verification email" ] , $"This will send a verification email to <strong>{Html.Encode(user.Email)}</strong>." , "Send" ) ) ;
2022-05-26 21:36:47 -07:00
}
[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 ) ;
2022-06-23 13:41:52 +09:00
( await _emailSenderFactory . GetEmailSender ( ) ) . SendEmailConfirmation ( user . GetMailboxAddress ( ) , callbackUrl ) ;
2022-05-26 21:36:47 -07:00
2024-10-17 15:51:40 +02:00
TempData [ WellKnownTempData . SuccessMessage ] = StringLocalizer [ "Verification email sent" ] . Value ;
2022-05-26 21:36:47 -07:00
return RedirectToAction ( nameof ( ListUsers ) ) ;
}
2024-09-12 05:31:57 +02:00
private async Task PrepareCreateUserViewData ( )
{
var emailSettings = await _SettingsRepository . GetSettingAsync < EmailSettings > ( ) ? ? new EmailSettings ( ) ;
ViewData [ "CanSendEmail" ] = emailSettings . IsComplete ( ) ;
ViewData [ "AllowRequestEmailConfirmation" ] = _policiesSettings . RequiresConfirmedEmail ;
}
2020-09-05 12:16:48 +02:00
}
2024-09-13 13:42:08 +01:00
public class ResetUserPasswordFromAdmin
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get ; set ; }
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get ; set ; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get ; set ; }
}
2020-09-05 12:16:48 +02:00
public class RegisterFromAdminViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get ; set ; }
[StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password (leave blank to generate invite-link)")]
public string Password { get ; set ; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get ; set ; }
[Display(Name = "Is administrator?")]
public bool IsAdmin { get ; set ; }
[Display(Name = "Email confirmed?")]
2021-12-31 16:59:02 +09:00
public bool EmailConfirmed { get ; set ; }
2024-09-12 05:31:57 +02:00
[Display(Name = "Send invitation email")]
public bool SendInvitationEmail { get ; set ; } = true ;
2020-09-05 12:16:48 +02:00
}
}