Added validation and fixed errors
This commit is contained in:
		| @@ -0,0 +1,4 @@ | ||||
| namespace ApplicationLayer.Services.AuthServices.Common | ||||
| { | ||||
|     public record AuthData(string Email, string Password); | ||||
| } | ||||
| @@ -1,23 +1,22 @@ | ||||
| using ApplicationLayer.Services.AuthServices.LoginService.Exceptions; | ||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | ||||
| using ApplicationLayer.Services.AuthServices.Requests; | ||||
| using Domains.Users; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.LoginService | ||||
| { | ||||
|     public class DevelopmentLoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService | ||||
|     { | ||||
|         async Task<string> ILoginService.LoginAsync(UserLoginRequest request, CancellationToken cancellationToken) | ||||
|         async Task<string> ILoginService.LoginAsync(string email, string password, CancellationToken cancellationToken) | ||||
|         { | ||||
|             if (request is { Email: "admin@mail.ru", Password: "admin" }) | ||||
|             if (email == "admin@mail.ru" && password == "admin") | ||||
|             { | ||||
|                 var admin = new User { Role = Role.Admin }; | ||||
|  | ||||
|                 return tokenGenerator.CreateToken(admin); | ||||
|             } | ||||
|  | ||||
|             var user = await users.FindByEmailAsync(request.Email, cancellationToken); | ||||
|             if (user is null || user.Password != request.Password) | ||||
|             var user = await users.FindByEmailAsync(email, cancellationToken); | ||||
|             if (user is null || user.Password != password) | ||||
|             { | ||||
|                 throw new IncorrectLoginDataException(); | ||||
|             } | ||||
|   | ||||
| @@ -1,12 +1,10 @@ | ||||
| using ApplicationLayer.Services.AuthServices.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.LoginService | ||||
| namespace ApplicationLayer.Services.AuthServices.LoginService | ||||
| { | ||||
|     /// Handles <see cref="UserLoginRequest"/> | ||||
|     /// Handles login requests | ||||
|     public interface ILoginService | ||||
|     { | ||||
|         /// Handle <see cref="UserLoginRequest"/> | ||||
|         /// Handle login request | ||||
|         /// <returns>JWT-token</returns> | ||||
|         Task<string> LoginAsync(UserLoginRequest request, CancellationToken cancellationToken); | ||||
|         Task<string> LoginAsync(string email, string password, CancellationToken cancellationToken); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,16 +1,15 @@ | ||||
| using ApplicationLayer.Services.AuthServices.LoginService.Exceptions; | ||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | ||||
| using ApplicationLayer.Services.AuthServices.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.LoginService | ||||
| { | ||||
|     /// <inheritdoc cref="ILoginService"/> | ||||
|     public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService | ||||
|     { | ||||
|         async Task<string> ILoginService.LoginAsync(UserLoginRequest request, CancellationToken cancellationToken) | ||||
|         async Task<string> ILoginService.LoginAsync(string email, string password, CancellationToken cancellationToken) | ||||
|         { | ||||
|             var user = await users.FindByEmailAsync(request.Email, cancellationToken); | ||||
|             if (user is null || user.Password != request.Password) | ||||
|             var user = await users.FindByEmailAsync(email, cancellationToken); | ||||
|             if (user is null || user.Password != password) | ||||
|             { | ||||
|                 throw new IncorrectLoginDataException(); | ||||
|             } | ||||
|   | ||||
| @@ -3,5 +3,5 @@ using ApplicationLayer.Services.AuthServices.Requests; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.RegisterService.Exceptions | ||||
| { | ||||
|     public class UserAlreadyExistsException(RegisterRequest request) : AlreadyExistsException($"User with email '{request.Email}' already exists"); | ||||
|     public class UserAlreadyExistsException(RegisterRequest request) : AlreadyExistsException($"User with email '{request.AuthData.Email}' already exists"); | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using ApplicationLayer.Services.Applicants.NeededServices; | ||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | ||||
| using ApplicationLayer.Services.AuthServices.RegisterService.Exceptions; | ||||
| using ApplicationLayer.Services.AuthServices.Requests; | ||||
| using AutoMapper; | ||||
| using Domains.ApplicantDomain; | ||||
| @@ -18,33 +17,11 @@ namespace ApplicationLayer.Services.AuthServices.RegisterService | ||||
|     { | ||||
|         async Task IRegisterService.RegisterApplicant(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||
|         { | ||||
|             //todo move to validation layer | ||||
|             if (await users.FindByEmailAsync(request.Email, cancellationToken) is not null) | ||||
|             { | ||||
|                 throw new UserAlreadyExistsException(request); | ||||
|             } | ||||
|  | ||||
|             var user = mapper.Map<User>(request); | ||||
|             var user = mapper.Map<User>(request.AuthData); | ||||
|             user.Role = Role.Applicant; | ||||
|  | ||||
|             var applicant = new Applicant | ||||
|             { | ||||
|                 Citizenship = request.Citizenship, | ||||
|                 CitizenshipByBirth = request.CitizenshipByBirth, | ||||
|                 Gender = request.Gender, | ||||
|                 Name = request.ApplicantName, | ||||
|                 Passport = request.Passport, | ||||
|                 BirthDate = request.BirthDate, | ||||
|                 FatherName = request.FatherName, | ||||
|                 JobTitle = request.JobTitle, | ||||
|                 MaritalStatus = request.MaritalStatus, | ||||
|                 MotherName = request.MotherName, | ||||
|                 UserId = user.Id, | ||||
|                 CityOfBirth = request.CityOfBirth, | ||||
|                 CountryOfBirth = request.CountryOfBirth, | ||||
|                 IsNonResident = request.IsNonResident, | ||||
|                 PlaceOfWork = request.PlaceOfWork | ||||
|             }; | ||||
|             var applicant = mapper.Map<Applicant>(request); | ||||
|             applicant.UserId = user.Id; | ||||
|  | ||||
|             await users.AddAsync(user, cancellationToken); | ||||
|             await applicants.AddAsync(applicant, cancellationToken); | ||||
| @@ -54,13 +31,7 @@ namespace ApplicationLayer.Services.AuthServices.RegisterService | ||||
|  | ||||
|         async Task IRegisterService.RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken) | ||||
|         { | ||||
|             //todo move to validation layer | ||||
|             if (await users.FindByEmailAsync(request.Email, cancellationToken) is not null) | ||||
|             { | ||||
|                 throw new UserAlreadyExistsException(request); | ||||
|             } | ||||
|  | ||||
|             var user = mapper.Map<User>(request); | ||||
|             var user = mapper.Map<User>(request.AuthData); | ||||
|             user.Role = Role.ApprovingAuthority; | ||||
|  | ||||
|             await users.AddAsync(user, cancellationToken); | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| using Domains.ApplicantDomain; | ||||
| using ApplicationLayer.Services.Applicants.Models; | ||||
| using ApplicationLayer.Services.AuthServices.Common; | ||||
| using Domains.ApplicantDomain; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests | ||||
| { | ||||
|     public record RegisterApplicantRequest( | ||||
|         string Email, | ||||
|         string Password, | ||||
|         AuthData AuthData, | ||||
|         Name ApplicantName, | ||||
|         Passport Passport, | ||||
|         DateTime BirthDate, | ||||
| @@ -17,6 +18,6 @@ namespace ApplicationLayer.Services.AuthServices.Requests | ||||
|         Name FatherName, | ||||
|         Name MotherName, | ||||
|         string JobTitle, | ||||
|         PlaceOfWork PlaceOfWork, | ||||
|         bool IsNonResident) : RegisterRequest(Email, Password); | ||||
|         PlaceOfWorkModel PlaceOfWork, | ||||
|         bool IsNonResident) : RegisterRequest(AuthData); | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests | ||||
| using ApplicationLayer.Services.AuthServices.Common; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests | ||||
| { | ||||
|     public record RegisterRequest(string Email, string Password); | ||||
|     public record RegisterRequest(AuthData AuthData); | ||||
| } | ||||
|   | ||||
| @@ -1,4 +0,0 @@ | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests | ||||
| { | ||||
|     public record UserLoginRequest(string Email, string Password); | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
| using ApplicationLayer.Services.AuthServices.Common; | ||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | ||||
| using Domains; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | ||||
| { | ||||
|     public class AuthDataValidator : AbstractValidator<AuthData> | ||||
|     { | ||||
|         public AuthDataValidator(IUsersRepository users) | ||||
|         { | ||||
|             RuleFor(d => d.Email) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Email can not be empty") | ||||
|                 .EmailAddress() | ||||
|                 .WithMessage("Email must be valid") | ||||
|                 .MaximumLength(ConfigurationConstraints.EmailLength) | ||||
|                 .WithMessage($"Email length must be less than {ConfigurationConstraints.EmailLength}") | ||||
|                 .MustAsync(async (email, ct) => | ||||
|                 { | ||||
|                     return await users.FindByEmailAsync(email, ct) is null; | ||||
|                 }) | ||||
|                 .WithMessage("Email already exists"); | ||||
|  | ||||
|             RuleFor(d => d.Password) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Password can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.PasswordLength) | ||||
|                 .WithMessage($"Password length must be less than {ConfigurationConstraints.PasswordLength}"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,28 @@ | ||||
| using Domains; | ||||
| using Domains.ApplicantDomain; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | ||||
| { | ||||
|     public class NameValidator : AbstractValidator<Name> | ||||
|     { | ||||
|         public NameValidator() | ||||
|         { | ||||
|             RuleFor(m => m.FirstName) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("First Name can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.NameLength) | ||||
|                 .WithMessage($"First Name length must be less than {ConfigurationConstraints.NameLength}"); | ||||
|  | ||||
|             RuleFor(m => m.Surname) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Surname can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.NameLength) | ||||
|                 .WithMessage($"Surname length must be less than {ConfigurationConstraints.NameLength}"); | ||||
|  | ||||
|             RuleFor(m => m.Patronymic) | ||||
|                 .MaximumLength(ConfigurationConstraints.NameLength) | ||||
|                 .WithMessage($"Patronymic length must be less than {ConfigurationConstraints.NameLength}"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,37 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using Domains; | ||||
| using Domains.ApplicantDomain; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | ||||
| { | ||||
|     public class PassportValidator : AbstractValidator<Passport> | ||||
|     { | ||||
|         public PassportValidator(IDateTimeProvider dateTimeProvider) | ||||
|         { | ||||
|             RuleFor(r => r.Issuer) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Passport issuer can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.IssuerNameLength) | ||||
|                 .WithMessage($"Passport issuer length must be less than {ConfigurationConstraints.IssuerNameLength}"); | ||||
|  | ||||
|             RuleFor(r => r.Number) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Passport number can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.PassportNumberLength) | ||||
|                 .WithMessage($"Passport number length must be less than {ConfigurationConstraints.PassportNumberLength}"); | ||||
|  | ||||
|             RuleFor(r => r.ExpirationDate) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Passport expiration date can not be empty") | ||||
|                 .GreaterThan(dateTimeProvider.Now()) | ||||
|                 .WithMessage("Can not approve visa for applicants with expired passport"); | ||||
|  | ||||
|             RuleFor(r => r.IssueDate) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Passport issue date can not be empty") | ||||
|                 .LessThanOrEqualTo(dateTimeProvider.Now()) | ||||
|                 .WithMessage("Passport issue date must be in past"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| using ApplicationLayer.Services.Applicants.Models; | ||||
| using Domains; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | ||||
| { | ||||
|     public class PlaceOfWorkModelValidator : AbstractValidator<PlaceOfWorkModel> | ||||
|     { | ||||
|         public PlaceOfWorkModelValidator() | ||||
|         { | ||||
|             RuleFor(p => p.Name) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Place of work name can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.PlaceOfWorkNameLength) | ||||
|                 .WithMessage($"Place of work name length must be less than {ConfigurationConstraints.PlaceOfWorkNameLength}"); | ||||
|  | ||||
|             RuleFor(p => p.PhoneNum) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Place of work phone number can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.PhoneNumberLength) | ||||
|                 .WithMessage($"Phone number length must be in range from {ConfigurationConstraints.PhoneNumberMinLength} to {ConfigurationConstraints.PhoneNumberLength}") | ||||
|                 .MinimumLength(ConfigurationConstraints.PhoneNumberMinLength) | ||||
|                 .WithMessage($"Phone number length must be in range from {ConfigurationConstraints.PhoneNumberMinLength} to {ConfigurationConstraints.PhoneNumberLength}"); | ||||
|  | ||||
|             RuleFor(p => p.Address.Country) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Country name of place of work can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||
|                 .WithMessage($"Country name of place of work length must be less than {ConfigurationConstraints.CountryNameLength}"); | ||||
|  | ||||
|             RuleFor(p => p.Address.City) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("City name of place of work can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.CityNameLength) | ||||
|                 .WithMessage($"City name of place of work length must be less than {ConfigurationConstraints.CityNameLength}"); | ||||
|  | ||||
|             RuleFor(p => p.Address.Street) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Street name of place of work can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.StreetNameLength) | ||||
|                 .WithMessage($"Street name of place of work length must be less than {ConfigurationConstraints.StreetNameLength}"); | ||||
|  | ||||
|             RuleFor(p => p.Address.Building) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Building of place of work can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||
|                 .WithMessage($"Building of place of work length must be less than {ConfigurationConstraints.BuildingNumberLength}"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,78 @@ | ||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | ||||
| using ApplicationLayer.Services.Applicants.Models; | ||||
| using ApplicationLayer.Services.AuthServices.Common; | ||||
| using Domains; | ||||
| using Domains.ApplicantDomain; | ||||
| using FluentValidation; | ||||
|  | ||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | ||||
| { | ||||
|     public class RegisterApplicantRequestValidator : AbstractValidator<RegisterApplicantRequest> | ||||
|     { | ||||
|         public RegisterApplicantRequestValidator( | ||||
|             IDateTimeProvider dateTimeProvider, | ||||
|             IValidator<Name> nameValidator, | ||||
|             IValidator<AuthData> authDataValidator, | ||||
|             IValidator<Passport> passportValidator, | ||||
|             IValidator<PlaceOfWorkModel> placeOfWorkModelValidator) | ||||
|         { | ||||
|             RuleFor(r => r.AuthData) | ||||
|                 .SetValidator(authDataValidator); | ||||
|  | ||||
|             RuleFor(r => r.ApplicantName) | ||||
|                 .SetValidator(nameValidator); | ||||
|  | ||||
|             RuleFor(r => r.FatherName) | ||||
|                 .SetValidator(nameValidator); | ||||
|  | ||||
|             RuleFor(r => r.MotherName) | ||||
|                 .SetValidator(nameValidator); | ||||
|  | ||||
|             RuleFor(r => r.Passport) | ||||
|                 .SetValidator(passportValidator); | ||||
|  | ||||
|             RuleFor(r => r.BirthDate) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Birth date can not be empty") | ||||
|                 .LessThanOrEqualTo(dateTimeProvider.Now().AddYears(-ConfigurationConstraints.ApplicantMinAge)) | ||||
|                 .WithMessage($"Applicant must be older than {ConfigurationConstraints.ApplicantMinAge}"); | ||||
|  | ||||
|             RuleFor(r => r.CountryOfBirth) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Country of birth can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||
|                 .WithMessage($"Country of birth name length must be less than {ConfigurationConstraints.CountryNameLength}"); | ||||
|  | ||||
|             RuleFor(r => r.CityOfBirth) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("City of birth can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.CityNameLength) | ||||
|                 .WithMessage($"City of birth name length must be less than {ConfigurationConstraints.CityNameLength}"); | ||||
|  | ||||
|             RuleFor(r => r.Citizenship) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Citizenship can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.CitizenshipLength) | ||||
|                 .WithMessage($"Citizenship length must be less than {ConfigurationConstraints.CitizenshipLength}"); | ||||
|  | ||||
|             RuleFor(r => r.CitizenshipByBirth) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Citizenship by birth can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.CitizenshipLength) | ||||
|                 .WithMessage($"Citizenship by birth length must be less than {ConfigurationConstraints.CitizenshipLength}"); | ||||
|  | ||||
|             RuleFor(r => r.Gender).IsInEnum(); | ||||
|  | ||||
|             RuleFor(r => r.MaritalStatus).IsInEnum(); | ||||
|  | ||||
|             RuleFor(r => r.JobTitle) | ||||
|                 .NotEmpty() | ||||
|                 .WithMessage("Title of job can not be empty") | ||||
|                 .MaximumLength(ConfigurationConstraints.JobTitleLength) | ||||
|                 .WithMessage($"Title of job length must be less than {ConfigurationConstraints.JobTitleLength}"); | ||||
|  | ||||
|             RuleFor(r => r.PlaceOfWork) | ||||
|                 .SetValidator(placeOfWorkModelValidator); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user