finalizare 1.0
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
+7
@@ -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;
|
||||
}
|
||||
+68
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
+52
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user