From 87d4c4f866297e7eed68c3df6e1ba229ea5875e1 Mon Sep 17 00:00:00 2001 From: Vzart Date: Thu, 15 Jun 2023 09:26:11 +0700 Subject: [PATCH] feat: resend email for admin --- .../Requests/Users/ResendEmailRequest.cs | 6 ++ src/Api/Controllers/UsersController.cs | 22 +++++- .../Users/Commands/ResendUserEmail.cs | 79 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/Api/Controllers/Payload/Requests/Users/ResendEmailRequest.cs create mode 100644 src/Application/Users/Commands/ResendUserEmail.cs diff --git a/src/Api/Controllers/Payload/Requests/Users/ResendEmailRequest.cs b/src/Api/Controllers/Payload/Requests/Users/ResendEmailRequest.cs new file mode 100644 index 00000000..22bc5dc0 --- /dev/null +++ b/src/Api/Controllers/Payload/Requests/Users/ResendEmailRequest.cs @@ -0,0 +1,6 @@ +namespace Api.Controllers.Payload.Requests.Users; + +public class ResendEmailRequest +{ + public Guid UserId { get; set; } +} \ No newline at end of file diff --git a/src/Api/Controllers/UsersController.cs b/src/Api/Controllers/UsersController.cs index 095e9605..a4f30660 100644 --- a/src/Api/Controllers/UsersController.cs +++ b/src/Api/Controllers/UsersController.cs @@ -13,7 +13,7 @@ public class UsersController : ApiControllerBase { private readonly ICurrentUserService _currentUserService; - public UsersController(ICurrentUserService currentUserService) + public UsersController(ICurrentUserService currentUserService, IMailService mailService) { _currentUserService = currentUserService; } @@ -160,4 +160,24 @@ public async Task>> Update([FromRoute] Guid userId, var result = await Mediator.Send(command); return Ok(Result.Succeed(result)); } + + /// + /// Resend email base on userId + /// + /// a UserDto of the user who Admin resend the email to + [RequiresRole(IdentityData.Roles.Admin)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [HttpPost("resend-email")] + public async Task>> ResendEmail(ResendEmailRequest request) + { + var command = new ResendUserEmail.Command() + { + UserId = request.UserId, + }; + + var result = await Mediator.Send(command); + + return Ok(Result.Succeed(result)); + } } diff --git a/src/Application/Users/Commands/ResendUserEmail.cs b/src/Application/Users/Commands/ResendUserEmail.cs new file mode 100644 index 00000000..ed908e69 --- /dev/null +++ b/src/Application/Users/Commands/ResendUserEmail.cs @@ -0,0 +1,79 @@ +using Application.Common.Exceptions; +using Application.Common.Interfaces; +using Application.Helpers; +using Application.Users.Queries; +using AutoMapper; +using Domain.Entities; +using MediatR; +using Microsoft.EntityFrameworkCore; +using NodaTime; + +namespace Application.Users.Commands; + +public class ResendUserEmail +{ + public record Command : IRequest + { + public Guid UserId { get; init; } + } + + public class CommandHandler : IRequestHandler + { + private readonly IApplicationDbContext _context; + private readonly IMailService _mailService; + private readonly IAuthDbContext _authContext; + private readonly IMapper _mapper; + private readonly ISecurityService _securityService; + + public CommandHandler(IApplicationDbContext context, IMailService mailService, IAuthDbContext authContext, IMapper mapper, ISecurityService securityService) + { + _context = context; + _mailService = mailService; + _authContext = authContext; + _mapper = mapper; + _securityService = securityService; + } + + public async Task Handle(Command request, CancellationToken cancellationToken) + { + var token = Guid.NewGuid().ToString(); + var password = StringUtil.RandomPassword(); + var salt = StringUtil.RandomSalt(); + var expirationDate = LocalDateTime.FromDateTime(DateTime.Now.AddDays(1)); + + var user = await _context.Users + .Include(x => x.Department) + .FirstOrDefaultAsync(x => x.Id.Equals(request.UserId),cancellationToken); + + if (user is null) + { + throw new KeyNotFoundException("User does not exist"); + } + + var resetPasswordToken = new ResetPasswordToken() + { + User = user, + TokenHash = SecurityUtil.Hash(token), + ExpirationDate = expirationDate, + IsInvalidated = false, + }; + + var pastResetPasswordToken = await _authContext.ResetPasswordTokens + .FirstOrDefaultAsync(x => x.User.Id.Equals(user.Id), cancellationToken); + + if (pastResetPasswordToken is null) + { + throw new KeyNotFoundException("Token does not exist."); + } + + _authContext.ResetPasswordTokens.Remove(pastResetPasswordToken); + await _authContext.ResetPasswordTokens.AddAsync(resetPasswordToken, cancellationToken); + user.PasswordSalt = salt ; + user.PasswordHash =_securityService.Hash(password, salt); + await _authContext.SaveChangesAsync(cancellationToken); + await _context.SaveChangesAsync(cancellationToken); + _mailService.SendResetPasswordHtmlMail(user.Email, password, token); + return _mapper.Map(user); + } + } +} \ No newline at end of file