From 2c8bfb707637611409f50e7bc7715961d21acbf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emre=20Co=C5=9Fkun?= Date: Sat, 23 Sep 2023 11:55:07 +0300 Subject: [PATCH] add new localized strings --- .../Identity/IEmailVerificationService.cs | 4 +- .../Identity/Jwt/RefreshRequestValidator.cs | 7 ++-- .../AuthServiceUnitTests.cs | 2 +- Unitagram.Identity/Services/AuthService.cs | 20 +++++----- .../Services/EmailVerificationService.cs | 40 +++++++++---------- .../Resources/SharedResources.en-us.resx | 21 ++++++++++ .../Resources/SharedResources.tr-TR.resx | 21 ++++++++++ 7 files changed, 79 insertions(+), 36 deletions(-) diff --git a/Unitagram.Application/Contracts/Identity/IEmailVerificationService.cs b/Unitagram.Application/Contracts/Identity/IEmailVerificationService.cs index b847e84..78d099d 100644 --- a/Unitagram.Application/Contracts/Identity/IEmailVerificationService.cs +++ b/Unitagram.Application/Contracts/Identity/IEmailVerificationService.cs @@ -5,6 +5,6 @@ namespace Unitagram.Application.Contracts.Identity; public interface IEmailVerificationService { - Task> GenerateAsync(Guid userId); - Task> ValidateAsync(Guid userId,string token); + Task> GenerateAsync(Guid userId, string email); + Task> ValidateAsync(Guid userId,string token); } \ No newline at end of file diff --git a/Unitagram.Application/Models/Identity/Jwt/RefreshRequestValidator.cs b/Unitagram.Application/Models/Identity/Jwt/RefreshRequestValidator.cs index 22b80c4..d5860f9 100644 --- a/Unitagram.Application/Models/Identity/Jwt/RefreshRequestValidator.cs +++ b/Unitagram.Application/Models/Identity/Jwt/RefreshRequestValidator.cs @@ -1,17 +1,18 @@ using FluentValidation; +using Unitagram.Application.Contracts.Localization; namespace Unitagram.Application.Models.Identity.Jwt; public class RefreshRequestValidator : AbstractValidator { - public RefreshRequestValidator() + public RefreshRequestValidator(ILocalizationService localization) { RuleFor(a => a.Token) - .NotEmpty().WithMessage("{PropertyName} can't be empty") + .NotEmpty().WithMessage(localization["TokenNotEmpty"]) .NotNull(); RuleFor(a => a.RefreshToken) - .NotEmpty().WithMessage("{PropertyName} can't be empty") + .NotEmpty().WithMessage(localization["TokenNotEmpty"]) .NotNull(); } } \ No newline at end of file diff --git a/Unitagram.Identity.UnitTests/AuthServiceUnitTests.cs b/Unitagram.Identity.UnitTests/AuthServiceUnitTests.cs index 5e73c82..b89afcb 100644 --- a/Unitagram.Identity.UnitTests/AuthServiceUnitTests.cs +++ b/Unitagram.Identity.UnitTests/AuthServiceUnitTests.cs @@ -259,7 +259,7 @@ public async Task Register_ValidCredentials_ReturnsRegisterResponse() .Returns(_fixture.Build().Create()); _verificationServiceMock - .Setup(u => u.GenerateAsync(It.IsAny())) + .Setup(u => u.GenerateAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(Result.Bottom); diff --git a/Unitagram.Identity/Services/AuthService.cs b/Unitagram.Identity/Services/AuthService.cs index e3f3344..0a62a6a 100644 --- a/Unitagram.Identity/Services/AuthService.cs +++ b/Unitagram.Identity/Services/AuthService.cs @@ -189,7 +189,7 @@ await _universityUserRepository.CreateAsync(new UniversityUser() user.RefreshTokenExpirationDateTime = jwtResponse.RefreshTokenExpirationDateTime; await _userManager.UpdateAsync(user); - await _verificationService.GenerateAsync(user.Id); + await _verificationService.GenerateAsync(user.Id, user.Email); _diagnosticContext.Set("CreatedUser", user.UserName); _diagnosticContext.Set("University", getUniversity.Name); @@ -204,14 +204,14 @@ public async Task> ConfirmEmail(EmailVerificat if (username == null) { - var exception = new UserNotFoundException(); + var exception = new UserNotFoundException(_localization["UserNotFound"]); return new Result(exception); } var user = await _userManager.FindByNameAsync(username); if (user == null) { - var exception = new UserNotFoundException(); + var exception = new UserNotFoundException(_localization["UsernameNotFound"]); return new Result(exception); } @@ -232,24 +232,24 @@ public async Task> GenerateOtpEmail(GenerateOtpReque if (username == null) { - var exception = new UserNotFoundException(); + var exception = new UserNotFoundException(_localization["UsernameNotFound"]); return new Result(exception); } var user = await _userManager.FindByNameAsync(username); if (user == null) { - var exception = new UserNotFoundException(); + var exception = new UserNotFoundException(_localization["UserNotFound"]); return new Result(exception); } if (user.EmailConfirmed) { - var exception = new EmailAlreadyConfirmedException(); + var exception = new EmailAlreadyConfirmedException(_localization["EmailAlreadyConfirmedException"]); return new Result(exception); } - var generateOtpResult = await _verificationService.GenerateAsync(user.Id); + var generateOtpResult = await _verificationService.GenerateAsync(user.Id, user.Email!); var result = generateOtpResult.Match>( _ => new GenerateOtpResponse(), @@ -266,7 +266,7 @@ private static string GetEmailDomain(RegisterRequest request) public async Task> RefreshToken(RefreshRequest request) { - var validator = new RefreshRequestValidator(); + var validator = new RefreshRequestValidator(_localization); var validationResult = await validator.ValidateAsync(request); if (validationResult.Errors.Any()) { @@ -281,7 +281,7 @@ public async Task> RefreshToken(RefreshRequest request) string? username = principal.FindFirstValue(ClaimTypes.NameIdentifier); if (username == null) { - var exception = new JwtTokenException(); + var exception = new JwtTokenException(_localization["UserNotFound"]); return new Result(exception); } @@ -289,7 +289,7 @@ public async Task> RefreshToken(RefreshRequest request) if (user is null) { - var exception = new UserNotFoundException(); + var exception = new UserNotFoundException(_localization["UserNotFound"]); return new Result(exception); } diff --git a/Unitagram.Identity/Services/EmailVerificationService.cs b/Unitagram.Identity/Services/EmailVerificationService.cs index 2afcbd6..5c270d1 100644 --- a/Unitagram.Identity/Services/EmailVerificationService.cs +++ b/Unitagram.Identity/Services/EmailVerificationService.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Unitagram.Application.Contracts.Email; using Unitagram.Application.Contracts.Identity; +using Unitagram.Application.Contracts.Localization; using Unitagram.Application.Contracts.Persistence; using Unitagram.Application.Exceptions.EmailVerification; using Unitagram.Application.Models.Email; @@ -20,36 +21,36 @@ public class EmailVerificationService : IEmailVerificationService private readonly UserManager _userManager; private readonly IEmailSender _emailSender; private readonly EmailOtpSettings _emailOtpSettings; + private readonly ILocalizationService _localization; public EmailVerificationService( IOtpConfirmationRepository otpConfirmationRepository, UserManager userManager, IEmailSender emailSender, - IOptions emailOtpSettings) + IOptions emailOtpSettings, + ILocalizationService localization) { _otpConfirmationRepository = otpConfirmationRepository; _userManager = userManager; _emailSender = emailSender; _emailOtpSettings = emailOtpSettings.Value; + _localization = localization; } - public async Task> GenerateAsync(Guid userId) + public async Task> GenerateAsync(Guid userId, string email) { var purpose = _emailOtpSettings.Name; var otpConfirmation = await _otpConfirmationRepository.GetByUserIdAndName(userId, purpose); - + if (otpConfirmation is null) { var token = GenerateRandom6DigitCode(); await CreateOtpConfirmation(userId, purpose, token); - var user = await _userManager.FindByIdAsync(userId.ToString()); - - await _emailSender.SendEmail(ConfirmationEmailTemplate.ToEmailMessage(user!.Email!, token), isBodyHtml: true); - + await _emailSender.SendEmail(ConfirmationEmailTemplate.ToEmailMessage(email, token), isBodyHtml: true); return Unit.Default; } @@ -59,18 +60,16 @@ public async Task> GenerateAsync(Guid userId) await UpdateOtpConfirmation(userId, purpose, token); - var user = await _userManager.FindByIdAsync(userId.ToString()); - - await _emailSender.SendEmail(ConfirmationEmailTemplate.ToEmailMessage(user!.Email!, token), isBodyHtml: true); + await _emailSender.SendEmail(ConfirmationEmailTemplate.ToEmailMessage(email, token), isBodyHtml: true); return Unit.Default; } var minutesDifference = CalculateMinutesDifference(otpConfirmation.RetryDateTimeUtc!.Value); - var exception = new OtpCodeTryAgainLaterException(); + var exception = new OtpCodeTryAgainLaterException(string.Format(_localization["OtpCodeTryAgainLaterException"], minutesDifference)); return new Result(exception); } - public async Task> ValidateAsync(Guid userId, string token) + public async Task> ValidateAsync(Guid userId, string token) { var purpose = _emailOtpSettings.Name; var maxRetryCount = _emailOtpSettings.RetryCount; @@ -80,15 +79,15 @@ public async Task> ValidateAsync(Guid userId, string token) if (otpConfirmation is null || IsRetryTimeElapsed(otpConfirmation)) { - var exception = new EmailOtpNotFoundException(); - return new Result(exception); + var exception = new EmailOtpNotFoundException(_localization["EmailOtpNotFoundException"]); + return new Result(exception); } // check max retry count is passed - if (otpConfirmation.RetryCount > maxRetryCount) + if (otpConfirmation.RetryCount >= maxRetryCount) { - var exception = new ReachedMaximumCodeUsageException(); - return new Result(exception); + var exception = new ReachedMaximumCodeUsageException(_localization["ReachedMaximumCodeUsageException"]); + return new Result(exception); } // if invalid token then increment maxRetryCount @@ -96,8 +95,9 @@ public async Task> ValidateAsync(Guid userId, string token) { otpConfirmation.RetryCount++; await _otpConfirmationRepository.UpdateAsync(otpConfirmation); - var exception = new InvalidCodeException(); - return new Result(exception); + var count = _emailOtpSettings.RetryCount - otpConfirmation.RetryCount; + var exception = new InvalidCodeException(string.Format(_localization["EmailInvalidCodeException"], count)); + return new Result(exception); } // if code reaches this part everything is ok and email can be confirmed @@ -110,7 +110,7 @@ public async Task> ValidateAsync(Guid userId, string token) // remove otpConfirmation await _otpConfirmationRepository.DeleteAsync(otpConfirmation); - return true; + return Unit.Default; } private string GenerateRandom6DigitCode() diff --git a/Unitagram.Infrastructure/Resources/SharedResources.en-us.resx b/Unitagram.Infrastructure/Resources/SharedResources.en-us.resx index 98d71f1..512e1b5 100644 --- a/Unitagram.Infrastructure/Resources/SharedResources.en-us.resx +++ b/Unitagram.Infrastructure/Resources/SharedResources.en-us.resx @@ -74,4 +74,25 @@ Username already exists. + + Username not found. + + + Please wait for {0} minutes before attempting to create new code again. + + + Code not found. Please resend code. + + + You've reached maximum code usage. Please resend code again. + + + Code is not correct. You have got {0} left. + + + Your email has already been confirmed successfully! + + + Token can't be empty. Please log in again. + \ No newline at end of file diff --git a/Unitagram.Infrastructure/Resources/SharedResources.tr-TR.resx b/Unitagram.Infrastructure/Resources/SharedResources.tr-TR.resx index e83a888..034d386 100644 --- a/Unitagram.Infrastructure/Resources/SharedResources.tr-TR.resx +++ b/Unitagram.Infrastructure/Resources/SharedResources.tr-TR.resx @@ -81,4 +81,25 @@ Kullanıcı adı kullanılıyor. + + Kullanıcı adı bulunamadı. + + + Yeni kod oluşturmak için lütfen tekrar {0} dakika sonra deneyin. + + + Kod bulunamadı. Lütfen kodu tekrar gönderiniz. + + + Maksimum tekrar sayısına ulaştınız. Lütfen kodu tekrar gönderiniz. + + + Kod doğru değil. {0} hakkınız kaldı. + + + E-postanız daha önce onaylanmıştır. + + + Giriş anahtarın boş olmamalıdır. Lütfen tekrar giriş yapmayı deneyiniz. + \ No newline at end of file