finalizare 1.0

This commit is contained in:
andrei-mihnea-cerbu
2024-05-21 12:10:53 +03:00
parent f7795f7519
commit 1cc1d34003
11268 changed files with 2102399 additions and 10909 deletions
@@ -1,45 +0,0 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
namespace Application.Endpoints.Authorization.Doctor;
public class DoctorLoginHandler
{
private readonly IDoctorRepository _database;
private readonly IHashingAlgorithms _hashingAlgorithms;
public DoctorLoginHandler(IDoctorRepository database, IHashingAlgorithms hashingAlgorithms)
{
_database = database;
_hashingAlgorithms = hashingAlgorithms;
}
public async Task<BaseResponse> Handle(LoginDto loginDTO)
{
loginDTO.Password = _hashingAlgorithms.SHA256Algorithm(loginDTO.Password);
var validation = new DoctorLoginValidation(_database);
var validationResult = await validation.ValidateAsync(loginDTO);
if (validationResult.IsValid)
{
var doctor = await _database.FindByEmailAsync(loginDTO.Email);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Authentication successful",
Data = doctor
};
}
var firstError = validationResult.Errors.FirstOrDefault();
var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
var errorMessage = firstError.ErrorMessage;
return new BaseResponse
{
StatusCode = errorCode,
Message = errorMessage,
Data = null
};
}
}
@@ -1,33 +0,0 @@
using Application.Services.Database.PostgreSQL;
using FluentValidation;
namespace Application.Endpoints.Authorization.Doctor;
public class DoctorLoginValidation : AbstractValidator<LoginDto>
{
private readonly IDoctorRepository _doctorRepository;
public DoctorLoginValidation(IDoctorRepository doctorRepository)
{
_doctorRepository = doctorRepository;
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.EmailAddress().WithMessage("Invalid email format.").WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MinimumLength(8).WithMessage("Password must be at least 8 characters long.")
.WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x)
.MustAsync(CredentialsMatch).WithMessage("Invalid credentials")
.WithErrorCode(HttpStatusCodes.Unauthorized.ToString());
}
private async Task<bool> CredentialsMatch(LoginDto dto, CancellationToken cancellationToken)
{
var code = await _doctorRepository.CredentialsMatch(dto.Email, dto.Password);
return code;
}
}
@@ -1,49 +0,0 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
namespace Application.Endpoints.Authorization.Doctor;
public class DoctorResetPasswordHandler
{
private readonly IDoctorRepository _doctorRepository;
private readonly IHashingAlgorithms _hashingAlgorithms;
public DoctorResetPasswordHandler(IDoctorRepository doctorRepository, IHashingAlgorithms hashingAlgorithms)
{
_doctorRepository = doctorRepository;
_hashingAlgorithms = hashingAlgorithms;
}
public async Task<BaseResponse> Handle(LoginDto resetDoctorDto)
{
var validation = new DoctorResetPasswordValidation(_doctorRepository, _hashingAlgorithms);
var validationResult = await validation.ValidateAsync(resetDoctorDto);
if (!validationResult.IsValid)
{
var firstError = validationResult.Errors.FirstOrDefault();
var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
var errorMessage = firstError.ErrorMessage;
return new BaseResponse
{
StatusCode = errorCode,
Message = errorMessage,
Data = null
};
}
var currentDoctor = await _doctorRepository.FindByEmailAsync(resetDoctorDto.Email);
var updatedDoctor = currentDoctor;
updatedDoctor.SetPassword(_hashingAlgorithms.SHA256Algorithm(resetDoctorDto.Password));
await _doctorRepository.UpdateAsync(updatedDoctor);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Password successfully changed!",
Data = null
};
}
}
@@ -1,45 +0,0 @@
using System.Net;
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
using FluentValidation;
namespace Application.Endpoints.Authorization.Doctor;
public class DoctorResetPasswordValidation : AbstractValidator<LoginDto>
{
private readonly IDoctorRepository _doctorRepository;
private readonly IHashingAlgorithms _hashingAlgorithms;
public DoctorResetPasswordValidation(IDoctorRepository doctorRepository, IHashingAlgorithms hashingAlgorithms)
{
_doctorRepository = doctorRepository;
_hashingAlgorithms = hashingAlgorithms;
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.EmailAddress().WithMessage("Invalid email format.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MustAsync(BeExistingDoctor).WithMessage("Patient with this email does not exist.")
.WithErrorCode(HttpStatusCodes.NotFound.ToString());
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.WithErrorCode(HttpStatusCode.BadRequest.ToString());
RuleFor(x => x)
.MustAsync(BeDifferentFromOldPassword).WithMessage("Password can't be as the previous.")
.WithErrorCode(HttpStatusCode.BadRequest.ToString()).WithErrorCode(HttpStatusCodes.BadRequest.ToString());
}
private async Task<bool> BeExistingDoctor(string email, CancellationToken cancellationToken)
{
var doctor = await _doctorRepository.FindByEmailAsync(email);
return doctor != null;
}
private async Task<bool> BeDifferentFromOldPassword(LoginDto dto, CancellationToken cancellationToken)
{
var currentPatient = await _doctorRepository.FindByEmailAsync(dto.Email);
return !_hashingAlgorithms.SHA256Algorithm(dto.Password)
.Equals(currentPatient?.Password, StringComparison.Ordinal);
}
}
@@ -1,7 +0,0 @@
namespace Application.Endpoints.Authorization;
public class LoginDto
{
public string Email;
public string Password;
}
@@ -1,43 +0,0 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
namespace Application.Endpoints.Authorization.Patient;
public class PatientLoginHandler
{
private readonly IPatientRepository _patientRepository;
private readonly IHashingAlgorithms _hashingAlgorithms;
public PatientLoginHandler(IPatientRepository patientRepository, IHashingAlgorithms hashingAlgorithms)
{
_patientRepository = patientRepository;
_hashingAlgorithms = hashingAlgorithms;
}
public async Task<BaseResponse> Handle(LoginDto loginDTO)
{
var validation = new PatientLoginValidation(_patientRepository, _hashingAlgorithms);
var validationResult = await validation.ValidateAsync(loginDTO);
if (validationResult.IsValid)
{
var patient = await _patientRepository.FindByEmailAsync(loginDTO.Email);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Authentication successful",
Data = patient
};
}
var firstError = validationResult.Errors.FirstOrDefault();
var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
var errorMessage = firstError.ErrorMessage;
return new BaseResponse
{
StatusCode = errorCode,
Message = errorMessage,
Data = null
};
}
}
@@ -1,37 +0,0 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
using FluentValidation;
namespace Application.Endpoints.Authorization.Patient;
public class PatientLoginValidation : AbstractValidator<LoginDto>
{
private readonly IPatientRepository _patientRepository;
private readonly IHashingAlgorithms _hashingAlgorithms;
public PatientLoginValidation(IPatientRepository patientRepository, IHashingAlgorithms hashingAlgorithms)
{
_patientRepository = patientRepository;
_hashingAlgorithms = hashingAlgorithms;
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.EmailAddress().WithMessage("Invalid email format.").WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MinimumLength(8).WithMessage("Password must be at least 8 characters long.")
.WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x)
.MustAsync(CredentialsMatch).WithMessage("Invalid credentials")
.WithErrorCode(HttpStatusCodes.Unauthorized.ToString());
}
private async Task<bool> CredentialsMatch(LoginDto dto, CancellationToken cancellationToken)
{
var code = await _patientRepository.CredentialsMatch(
dto.Email, _hashingAlgorithms.SHA256Algorithm(dto.Password));
return code;
}
}
@@ -1,49 +0,0 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
namespace Application.Endpoints.Authorization.Patient;
public class PatientResetPasswordHandler
{
private readonly IHashingAlgorithms _hashingAlgorithms;
private readonly IPatientRepository _patientRepository;
public PatientResetPasswordHandler(IPatientRepository patientRepository, IHashingAlgorithms hashingAlgorithms)
{
_patientRepository = patientRepository;
_hashingAlgorithms = hashingAlgorithms;
}
public async Task<BaseResponse> Handle(LoginDto patientResetPasswordDto)
{
var validation = new PatientResetPasswordValidation(_patientRepository, _hashingAlgorithms);
var validationResult = await validation.ValidateAsync(patientResetPasswordDto);
if (!validationResult.IsValid)
{
var firstError = validationResult.Errors.FirstOrDefault();
var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
var errorMessage = firstError.ErrorMessage;
return new BaseResponse
{
StatusCode = errorCode,
Message = errorMessage,
Data = null
};
}
var currentPatient = await _patientRepository.FindByEmailAsync(patientResetPasswordDto.Email);
var updatedPatient = currentPatient;
updatedPatient.SetPassword(_hashingAlgorithms.SHA256Algorithm(patientResetPasswordDto.Password));
await _patientRepository.UpdateAsync(updatedPatient);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Password successfully changed!",
Data = null
};
}
}
@@ -1,46 +0,0 @@
using System.Net;
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
using FluentValidation;
namespace Application.Endpoints.Authorization.Patient;
public class PatientResetPasswordValidation : AbstractValidator<LoginDto>
{
private readonly IPatientRepository _patientRepository;
private readonly IHashingAlgorithms _hashingAlgorithms;
public PatientResetPasswordValidation(IPatientRepository patientRepository,
IHashingAlgorithms hashingAlgorithms)
{
_patientRepository = patientRepository;
_hashingAlgorithms = hashingAlgorithms;
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.EmailAddress().WithMessage("Invalid email format.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MustAsync(BeExistingPatient).WithMessage("Patient with this email does not exist.")
.WithErrorCode(HttpStatusCodes.NotFound.ToString());
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.WithErrorCode(HttpStatusCode.BadRequest.ToString());
RuleFor(x => x)
.MustAsync(BeDifferentFromOldPassword).WithMessage("Password can't be as the previous.")
.WithErrorCode(HttpStatusCode.BadRequest.ToString()).WithErrorCode(HttpStatusCodes.BadRequest.ToString());
}
private async Task<bool> BeExistingPatient(string email, CancellationToken cancellationToken)
{
var patient = await _patientRepository.FindByEmailAsync(email);
return patient != null;
}
private async Task<bool> BeDifferentFromOldPassword(LoginDto dto, CancellationToken cancellationToken)
{
var currentPatient = await _patientRepository.FindByEmailAsync(dto.Email);
return !_hashingAlgorithms.SHA256Algorithm(dto.Password)
.Equals(currentPatient?.Password, StringComparison.Ordinal);
}
}
@@ -0,0 +1,6 @@
namespace Application.Endpoints.Authorization.RefreshToken;
public class RefreshJwtCommand
{
public string Token { get; set; } = string.Empty;
}
@@ -0,0 +1,30 @@
using Application.Services.Jwt;
namespace Application.Endpoints.Authorization.RefreshToken;
public class RefreshJwtHandler(IJwtService jwtService)
{
public async Task<BaseResponse> Handle(RefreshJwtCommand command, CancellationToken cancellationToken)
{
var validator = new RefreshJwtValidator(jwtService);
var validationResult = await validator.ValidateAsync(command, cancellationToken);
if (!validationResult.IsValid)
{
var firstError = validationResult.Errors.FirstOrDefault();
return new BaseResponse
{
StatusCode = HttpStatusCodes.Unauthorized,
Message = firstError?.ErrorMessage
};
}
var newToken = jwtService.RefreshToken(command.Token);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Token refreshed successfully.",
Data = newToken
};
}
}
@@ -0,0 +1,23 @@
using Application.Services.Jwt;
using FluentValidation;
namespace Application.Endpoints.Authorization.RefreshToken;
public class RefreshJwtValidator : AbstractValidator<RefreshJwtCommand>
{
private readonly IJwtService _jwtService;
public RefreshJwtValidator(IJwtService jwtService)
{
_jwtService = jwtService;
RuleFor(x => x.Token)
.NotEmpty().WithMessage("Token is required.")
.Must(BeAValidToken).WithMessage("Token is invalid or expired.");
}
private bool BeAValidToken(string token)
{
return _jwtService.ValidateJwtToken(token);
}
}
@@ -0,0 +1,7 @@
namespace Application.Endpoints.Authorization.UserLogin;
public class UserLoginCommand
{
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
@@ -0,0 +1,79 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
using Application.Services.Jwt;
using Domain;
namespace Application.Endpoints.Authorization.UserLogin;
public class UserLoginHandler(
IJwtService jwtService,
IHashingAlgorithms hashingAlgorithms,
IDoctorRepository doctorRepository,
IPatientRepository patientRepository,
IAdminRepository adminRepository)
{
public async Task<BaseResponse> Handle(UserLoginCommand request, CancellationToken token)
{
var validator = new UserLoginValidator();
var result = await validator.ValidateAsync(request, token);
if (!result.IsValid)
{
var firstError = result.Errors.FirstOrDefault();
var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
var errorMessage = firstError.ErrorMessage;
return new BaseResponse
{
StatusCode = errorCode,
Message = errorMessage,
Data = null
};
}
var email = request.Email;
var password = hashingAlgorithms.Sha256Algorithm(request.Password);
if (await doctorRepository.CredentialsMatch(email, password, token))
{
var doctor = await doctorRepository.FindByEmailAsync(email, token);
var authToken = jwtService.GenerateJwtToken(doctor.Id, UserRoles.Doctor, doctor.Name);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Doctor logged in successfully.",
Data = authToken
};
}
if (await patientRepository.CredentialsMatch(email, password, token))
{
var patient = await patientRepository.FindByEmailAsync(email, token);
var authToken = jwtService.GenerateJwtToken(patient.Id, UserRoles.Patient, patient.Name);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Patient logged in successfully.",
Data = authToken
};
}
if (await adminRepository.CredentialsMatch(email, password, token))
{
var admin = await adminRepository.FindByEmailAsync(email, token);
var authToken = jwtService.GenerateJwtToken(admin.Id, UserRoles.Admin, admin.Name);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Admin logged in successfully.",
Data = authToken
};
}
return new BaseResponse
{
StatusCode = HttpStatusCodes.NotFound,
Message = "User not registered in our system.",
Data = null
};
}
}
@@ -0,0 +1,18 @@
using FluentValidation;
namespace Application.Endpoints.Authorization.UserLogin;
public class UserLoginValidator : AbstractValidator<UserLoginCommand>
{
public UserLoginValidator()
{
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.EmailAddress().WithMessage("Invalid email format.").WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MinimumLength(8).WithMessage("Password must be at least 8 characters long.")
.WithErrorCode(HttpStatusCodes.BadRequest.ToString());
}
}
@@ -1,8 +0,0 @@
namespace Application.Endpoints.Authorization;
public class UserLoginModel
{
public string? UserType { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
@@ -0,0 +1,9 @@
namespace Application.Endpoints.Authorization.UserRegister;
public class UserRegisterCommand
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string Role { get; set; } = string.Empty;
}
@@ -0,0 +1,73 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.Email;
using Application.Services.HashingAlgorithms;
using Domain;
using Domain.Entities;
namespace Application.Endpoints.Authorization.UserRegister;
public class UserRegisterHandler(
IEmailService emailService,
IHashingAlgorithms hashingAlgorithms,
IDoctorRepository doctorRepository,
IPatientRepository patientRepository,
IAdminRepository adminRepository)
{
public async Task<BaseResponse> Handle(UserRegisterCommand request, CancellationToken token)
{
var validator = new UserRegisterValidator(
patientRepository, doctorRepository, adminRepository);
var result = await validator.ValidateAsync(request, token);
if (!result.IsValid)
{
var firstError = result.Errors.FirstOrDefault();
var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
var errorMessage = firstError.ErrorMessage;
return new BaseResponse
{
StatusCode = errorCode,
Message = errorMessage,
Data = null
};
}
switch (request.Role)
{
case UserRoles.Admin:
var admin = new Admin();
admin.SetName(request.Name);
admin.SetEmail(request.Email);
admin.SetPassword(hashingAlgorithms.Sha256Algorithm(request.Password));
await adminRepository.AddAsync(admin, token);
break;
case UserRoles.Doctor:
var doctor = new Doctor();
doctor.SetName(request.Name);
doctor.SetEmail(request.Email);
doctor.SetPassword(hashingAlgorithms.Sha256Algorithm(request.Password));
await doctorRepository.AddAsync(doctor, token);
break;
case UserRoles.Patient:
var patient = new Patient();
patient.SetName(request.Name);
patient.SetEmail(request.Email);
patient.SetPassword(hashingAlgorithms.Sha256Algorithm(request.Password));
await patientRepository.AddAsync(patient, token);
break;
}
var emailBody = emailService.GenerateCredentialsEmailBody(request.Name, request.Email, request.Password);
await emailService.SendEmailAsync(request.Email, emailService.GetSuccessfulRegistrationSubject(), emailBody);
return new BaseResponse
{
StatusCode = HttpStatusCodes.Created,
Message = "User created successfully",
Data = null
};
}
}
@@ -0,0 +1,57 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.HashingAlgorithms;
using Domain;
using FluentValidation;
namespace Application.Endpoints.Authorization.UserRegister;
public class UserRegisterValidator : AbstractValidator<UserRegisterCommand>
{
private readonly IAdminRepository _adminRepository;
private readonly IDoctorRepository _doctorRepository;
private readonly IPatientRepository _patientRepository;
public UserRegisterValidator(IPatientRepository patientRepository,
IDoctorRepository doctorRepository, IAdminRepository adminRepository)
{
_patientRepository = patientRepository;
_doctorRepository = doctorRepository;
_adminRepository = adminRepository;
RuleFor(x => x.Name)
.NotEmpty().WithMessage("Name is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MaximumLength(30).WithMessage("Maximum name length of 30 characters")
.WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.EmailAddress().WithMessage("Invalid email format.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MustAsync(async (email, token) => await AccountNotRegistered(email, token))
.WithMessage("Account already registered in system.").WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MinimumLength(8).WithMessage("Password must be at least 8 characters long.")
.WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x.Role)
.NotEmpty().WithMessage("Role is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.Must(BeAValidRole).WithMessage("Invalid role specified.")
.WithErrorCode(HttpStatusCodes.BadRequest.ToString());
}
private bool BeAValidRole(string role)
{
var validRoles = new[] { UserRoles.Admin, UserRoles.Doctor, UserRoles.Patient };
return validRoles.Contains(role);
}
private async Task<bool> AccountNotRegistered(string email, CancellationToken token)
{
var patient = await _patientRepository.FindByEmailAsync(email, token);
var doctor = await _doctorRepository.FindByEmailAsync(email, token);
var admin = await _adminRepository.FindByEmailAsync(email, token);
return patient == null && doctor == null && admin == null;
}
}
@@ -0,0 +1,7 @@
namespace Application.Endpoints.Authorization.UserResetPassword;
public class UserResetPasswordCommand
{
public string Email { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
}
@@ -0,0 +1,68 @@
using Application.Services.Database.PostgreSQL;
using Application.Services.Email;
using Application.Services.HashingAlgorithms;
namespace Application.Endpoints.Authorization.UserResetPassword;
public class UserResetPasswordHandler(
IEmailService emailService,
IHashingAlgorithms hashingAlgorithms,
IDoctorRepository doctorRepository,
IPatientRepository patientRepository,
IAdminRepository adminRepository)
{
public async Task<BaseResponse> Handle(UserResetPasswordCommand request, CancellationToken token)
{
var validator = new UserResetPasswordValidator(
patientRepository, doctorRepository, adminRepository);
var result = await validator.ValidateAsync(request, token);
if (!result.IsValid)
{
var firstError = result.Errors.FirstOrDefault();
var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
var errorMessage = firstError.ErrorMessage;
return new BaseResponse
{
StatusCode = errorCode,
Message = errorMessage,
Data = null
};
}
string? name = null;
var patient = await patientRepository.FindByEmailAsync(request.Email, token);
if (patient != null)
{
name = patient.Name;
patient.SetPassword(hashingAlgorithms.Sha256Algorithm(request.Password));
await patientRepository.UpdateAsync(patient, token);
}
var doctor = await doctorRepository.FindByEmailAsync(request.Email, token);
if (doctor != null)
{
name = doctor.Name;
doctor.SetPassword(hashingAlgorithms.Sha256Algorithm(request.Password));
await doctorRepository.UpdateAsync(doctor, token);
}
var admin = await adminRepository.FindByEmailAsync(request.Email, token);
if (admin != null)
{
name = admin.Name;
admin.SetPassword(hashingAlgorithms.Sha256Algorithm(request.Password));
await adminRepository.UpdateAsync(admin, token);
}
var emailBody = emailService.GenerateResetCredentialsEmailBody(name, request.Email, request.Password);
await emailService.SendEmailAsync(request.Email, emailService.GetSuccessfulPasswordResetSubject(), emailBody);
return new BaseResponse
{
StatusCode = HttpStatusCodes.OK,
Message = "Password updated successfully.",
Data = null
};
}
}
@@ -0,0 +1,52 @@
using Application.Services.Database.PostgreSQL;
using Domain;
using FluentValidation;
namespace Application.Endpoints.Authorization.UserResetPassword;
public class UserResetPasswordValidator : AbstractValidator<UserResetPasswordCommand>
{
private readonly IAdminRepository _adminRepository;
private readonly IDoctorRepository _doctorRepository;
private readonly IPatientRepository _patientRepository;
public UserResetPasswordValidator(IPatientRepository patientRepository,
IDoctorRepository doctorRepository, IAdminRepository adminRepository)
{
_patientRepository = patientRepository;
_doctorRepository = doctorRepository;
_adminRepository = adminRepository;
RuleFor(x => x.Email)
.NotEmpty().WithMessage("Email is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.EmailAddress().WithMessage("Invalid email format.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MustAsync(async (email, token) => await AccountRegistered(email, token))
.WithMessage("Account already registered in system.").WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x.Password)
.NotEmpty().WithMessage("Password is required.").WithErrorCode(HttpStatusCodes.BadRequest.ToString())
.MinimumLength(8).WithMessage("Password must be at least 8 characters long.")
.WithErrorCode(HttpStatusCodes.BadRequest.ToString());
RuleFor(x => x)
.MustAsync(async (request, token) =>
await AccountRegistered(request.Email, token))
.WithMessage("Account already registered in system.").WithErrorCode(HttpStatusCodes.BadRequest.ToString());
}
private bool BeAValidRole(string role)
{
var validRoles = new[] { UserRoles.Admin, UserRoles.Doctor, UserRoles.Patient };
return validRoles.Contains(role);
}
private async Task<bool> AccountRegistered(string email, CancellationToken token)
{
var patient = await _patientRepository.FindByEmailAsync(email, token);
var doctor = await _doctorRepository.FindByEmailAsync(email, token);
var admin = await _adminRepository.FindByEmailAsync(email, token);
return patient != null || doctor != null || admin != null;
}
}