| @@ -1,4 +1,3 @@ | |||||||
| namespace ApplicationLayer.GeneralExceptions | namespace ApplicationLayer.GeneralExceptions; | ||||||
| { |  | ||||||
|     public class AlreadyExistsException(string message) : ApiException(message); | public class AlreadyExistsException(string message) : ApiException(message); | ||||||
| } |  | ||||||
| @@ -1,4 +1,3 @@ | |||||||
| namespace ApplicationLayer.GeneralExceptions | namespace ApplicationLayer.GeneralExceptions; | ||||||
| { |  | ||||||
|     public class ApiException(string message) : Exception(message); | public class ApiException(string message) : Exception(message); | ||||||
| } |  | ||||||
| @@ -1,8 +1,7 @@ | |||||||
| namespace ApplicationLayer.InfrastructureServicesInterfaces | namespace ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
|  |  | ||||||
|  | public interface IDateTimeProvider | ||||||
| { | { | ||||||
|     public interface IDateTimeProvider |     /// Returns current date and time | ||||||
|     { |     DateTime Now(); | ||||||
|         /// Returns current date and time |  | ||||||
|         DateTime Now(); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,8 +1,7 @@ | |||||||
| namespace ApplicationLayer.InfrastructureServicesInterfaces | namespace ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
|  |  | ||||||
|  | public interface IUserIdProvider | ||||||
| { | { | ||||||
|     public interface IUserIdProvider |     /// Returns identifier of authenticated user who sent the request | ||||||
|     { |     Guid GetUserId(); | ||||||
|         /// Returns identifier of authenticated user who sent the request |  | ||||||
|         Guid GetUserId(); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,50 +1,49 @@ | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Applicants.Models | namespace ApplicationLayer.Services.Applicants.Models; | ||||||
|  |  | ||||||
|  | /// Model of <see cref="Applicant"/> | ||||||
|  | public class ApplicantModel | ||||||
| { | { | ||||||
|     /// Model of <see cref="Applicant"/> |     /// <inheritdoc cref="Applicant.Name"/> | ||||||
|     public class ApplicantModel |     public Name Name { get; set; } = null!; | ||||||
|     { |  | ||||||
|         /// <inheritdoc cref="Applicant.Name"/> |  | ||||||
|         public Name Name { get; set; } = null!; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.Passport"/> |     /// <inheritdoc cref="Applicant.Passport"/> | ||||||
|         public Passport Passport { get; set; } = null!; |     public Passport Passport { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.BirthDate"/> |     /// <inheritdoc cref="Applicant.BirthDate"/> | ||||||
|         public DateTime BirthDate { get; set; } |     public DateTime BirthDate { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.CountryOfBirth"/> |     /// <inheritdoc cref="Applicant.CountryOfBirth"/> | ||||||
|         public string CountryOfBirth { get; set; } = null!; |     public string CountryOfBirth { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.CityOfBirth"/> |     /// <inheritdoc cref="Applicant.CityOfBirth"/> | ||||||
|         public string CityOfBirth { get; set; } = null!; |     public string CityOfBirth { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.Citizenship"/> |     /// <inheritdoc cref="Applicant.Citizenship"/> | ||||||
|         public string Citizenship { get; set; } = null!; |     public string Citizenship { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.CitizenshipByBirth"/> |     /// <inheritdoc cref="Applicant.CitizenshipByBirth"/> | ||||||
|         public string CitizenshipByBirth { get; set; } = null!; |     public string CitizenshipByBirth { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.Gender"/> |     /// <inheritdoc cref="Applicant.Gender"/> | ||||||
|         public Gender Gender { get; set; } |     public Gender Gender { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.MaritalStatus"/> |     /// <inheritdoc cref="Applicant.MaritalStatus"/> | ||||||
|         public MaritalStatus MaritalStatus { get; set; } |     public MaritalStatus MaritalStatus { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.FatherName"/> |     /// <inheritdoc cref="Applicant.FatherName"/> | ||||||
|         public Name FatherName { get; set; } = null!; |     public Name FatherName { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.MotherName"/> |     /// <inheritdoc cref="Applicant.MotherName"/> | ||||||
|         public Name MotherName { get; set; } = null!; |     public Name MotherName { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.JobTitle"/> |     /// <inheritdoc cref="Applicant.JobTitle"/> | ||||||
|         public string JobTitle { get; set; } = null!; |     public string JobTitle { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.PlaceOfWork"/> |     /// <inheritdoc cref="Applicant.PlaceOfWork"/> | ||||||
|         public PlaceOfWork PlaceOfWork { get; set; } = null!; |     public PlaceOfWork PlaceOfWork { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="Applicant.IsNonResident"/> |     /// <inheritdoc cref="Applicant.IsNonResident"/> | ||||||
|         public bool IsNonResident { get; set; } |     public bool IsNonResident { get; set; } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,16 +1,15 @@ | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Applicants.Models | namespace ApplicationLayer.Services.Applicants.Models; | ||||||
|  |  | ||||||
|  | public class PlaceOfWorkModel | ||||||
| { | { | ||||||
|     public class PlaceOfWorkModel |     /// Name of hirer | ||||||
|     { |     public string Name { get; set; } = null!; | ||||||
|         /// Name of hirer |  | ||||||
|         public string Name { get; set; } = null!; |  | ||||||
|  |  | ||||||
|         /// Address of hirer |     /// Address of hirer | ||||||
|         public Address Address { get; set; } = null!; |     public Address Address { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// Phone number of hirer |     /// Phone number of hirer | ||||||
|         public string PhoneNum { get; set; } = null!; |     public string PhoneNum { get; set; } = null!; | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,4 +1,3 @@ | |||||||
| namespace ApplicationLayer.Services.AuthServices.Common | namespace ApplicationLayer.Services.AuthServices.Common; | ||||||
| { |  | ||||||
|     public record AuthData(string Email, string Password); | public record AuthData(string Email, string Password); | ||||||
| } |  | ||||||
| @@ -2,12 +2,12 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | using ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.LoginService | namespace ApplicationLayer.Services.AuthServices.LoginService; | ||||||
|  |  | ||||||
|  | public class DevelopmentLoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService | ||||||
| { | { | ||||||
|     public class DevelopmentLoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService |     async Task<string> ILoginService.LoginAsync(string email, string password, CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         async Task<string> ILoginService.LoginAsync(string email, string password, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             if (email == "admin@mail.ru" && password == "admin") |             if (email == "admin@mail.ru" && password == "admin") | ||||||
|             { |             { | ||||||
|                 var admin = new User { Role = Role.Admin }; |                 var admin = new User { Role = Role.Admin }; | ||||||
| @@ -23,5 +23,4 @@ namespace ApplicationLayer.Services.AuthServices.LoginService | |||||||
|  |  | ||||||
|             return tokenGenerator.CreateToken(user); |             return tokenGenerator.CreateToken(user); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| using ApplicationLayer.GeneralExceptions; | using ApplicationLayer.GeneralExceptions; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.LoginService.Exceptions | namespace ApplicationLayer.Services.AuthServices.LoginService.Exceptions; | ||||||
| { |  | ||||||
|     public class IncorrectLoginDataException() : ApiException("Incorrect email or password"); | public class IncorrectLoginDataException() : ApiException("Incorrect email or password"); | ||||||
| } |  | ||||||
| @@ -1,10 +1,9 @@ | |||||||
| namespace ApplicationLayer.Services.AuthServices.LoginService | namespace ApplicationLayer.Services.AuthServices.LoginService; | ||||||
|  |  | ||||||
|  | /// Handles login requests | ||||||
|  | public interface ILoginService | ||||||
| { | { | ||||||
|     /// Handles login requests |     /// Handle login request | ||||||
|     public interface ILoginService |     /// <returns>JWT-token</returns> | ||||||
|     { |     Task<string> LoginAsync(string email, string password, CancellationToken cancellationToken); | ||||||
|         /// Handle login request |  | ||||||
|         /// <returns>JWT-token</returns> |  | ||||||
|         Task<string> LoginAsync(string email, string password, CancellationToken cancellationToken); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.LoginService.Exceptions; | using ApplicationLayer.Services.AuthServices.LoginService.Exceptions; | ||||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | using ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.LoginService | namespace ApplicationLayer.Services.AuthServices.LoginService; | ||||||
|  |  | ||||||
|  | /// <inheritdoc cref="ILoginService"/> | ||||||
|  | public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService | ||||||
| { | { | ||||||
|     /// <inheritdoc cref="ILoginService"/> |     async Task<string> ILoginService.LoginAsync(string email, string password, CancellationToken cancellationToken) | ||||||
|     public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService |  | ||||||
|     { |     { | ||||||
|         async Task<string> ILoginService.LoginAsync(string email, string password, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             var user = await users.FindByEmailAsync(email, cancellationToken); |             var user = await users.FindByEmailAsync(email, cancellationToken); | ||||||
|             if (user is null || user.Password != password) |             if (user is null || user.Password != password) | ||||||
|             { |             { | ||||||
| @@ -16,5 +16,4 @@ namespace ApplicationLayer.Services.AuthServices.LoginService | |||||||
|  |  | ||||||
|             return tokenGenerator.CreateToken(user); |             return tokenGenerator.CreateToken(user); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,9 +1,10 @@ | |||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.NeededServices | namespace ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
|  |  | ||||||
|  | /// Generates jwt-tokens | ||||||
|  | public interface ITokenGenerator | ||||||
| { | { | ||||||
|     public interface ITokenGenerator |     /// returns jwt-token for specific user | ||||||
|     { |     string CreateToken(User user); | ||||||
|         string CreateToken(User user); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,21 +1,20 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | using ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.NeededServices | namespace ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
| { |  | ||||||
|     /// Repository pattern for <see cref="User"/> |  | ||||||
|     public interface IUsersRepository : IGenericRepository<User> |  | ||||||
|     { |  | ||||||
|         /// Find <see cref="User"/> by email |  | ||||||
|         /// <param name="email"><see cref="User"/>'s email</param> |  | ||||||
|         /// <param name="cancellationToken">Cancellation token</param> |  | ||||||
|         /// <returns>User or null if not found</returns> |  | ||||||
|         Task<User?> FindByEmailAsync(string email, CancellationToken cancellationToken); |  | ||||||
|  |  | ||||||
|         /// Returns all accounts with specific role | /// Repository pattern for <see cref="User"/> | ||||||
|         /// <param name="role">role</param> | public interface IUsersRepository : IGenericRepository<User> | ||||||
|         /// <param name="cancellationToken">cancellation token</param> | { | ||||||
|         /// <returns>list of accounts</returns> |     /// Find <see cref="User"/> by email | ||||||
|         Task<List<User>> GetAllOfRoleAsync(Role role, CancellationToken cancellationToken); |     /// <param name="email"><see cref="User"/>'s email</param> | ||||||
|     } |     /// <param name="cancellationToken">Cancellation token</param> | ||||||
|  |     /// <returns>User or null if not found</returns> | ||||||
|  |     Task<User?> FindByEmailAsync(string email, CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|  |     /// Returns all accounts with specific role | ||||||
|  |     /// <param name="role">role</param> | ||||||
|  |     /// <param name="cancellationToken">cancellation token</param> | ||||||
|  |     /// <returns>list of accounts</returns> | ||||||
|  |     Task<List<User>> GetAllOfRoleAsync(Role role, CancellationToken cancellationToken); | ||||||
| } | } | ||||||
| @@ -1,14 +1,13 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.Requests; | using ApplicationLayer.Services.AuthServices.Requests; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.RegisterService | namespace ApplicationLayer.Services.AuthServices.RegisterService; | ||||||
| { |  | ||||||
|     /// Handles register request |  | ||||||
|     public interface IRegisterService |  | ||||||
|     { |  | ||||||
|         /// Handle <see cref="RegisterApplicantRequest"/> |  | ||||||
|         Task RegisterApplicant(RegisterApplicantRequest request, CancellationToken cancellationToken); |  | ||||||
|  |  | ||||||
|         /// Handles <see cref="RegisterRequest"/> and adds approving authority account | /// Handles register request | ||||||
|         Task RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken); | public interface IRegisterService | ||||||
|     } | { | ||||||
|  |     /// Handle <see cref="RegisterApplicantRequest"/> | ||||||
|  |     Task RegisterApplicant(RegisterApplicantRequest request, CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|  |     /// Handles <see cref="RegisterRequest"/> and adds approving authority account | ||||||
|  |     Task RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken); | ||||||
| } | } | ||||||
| @@ -6,37 +6,36 @@ using AutoMapper; | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.RegisterService | namespace ApplicationLayer.Services.AuthServices.RegisterService; | ||||||
|  |  | ||||||
|  | /// <inheritdoc cref="IRegisterService"/> | ||||||
|  | public class RegisterService( | ||||||
|  |     IUsersRepository users, | ||||||
|  |     IApplicantsRepository applicants, | ||||||
|  |     IUnitOfWork unitOfWork, | ||||||
|  |     IMapper mapper) : IRegisterService | ||||||
| { | { | ||||||
|     /// <inheritdoc cref="IRegisterService"/> |     async Task IRegisterService.RegisterApplicant(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||||
|     public class RegisterService( |  | ||||||
|         IUsersRepository users, |  | ||||||
|         IApplicantsRepository applicants, |  | ||||||
|         IUnitOfWork unitOfWork, |  | ||||||
|         IMapper mapper) : IRegisterService |  | ||||||
|     { |     { | ||||||
|         async Task IRegisterService.RegisterApplicant(RegisterApplicantRequest request, CancellationToken cancellationToken) |         var user = mapper.Map<User>(request.AuthData); | ||||||
|         { |         user.Role = Role.Applicant; | ||||||
|             var user = mapper.Map<User>(request.AuthData); |  | ||||||
|             user.Role = Role.Applicant; |  | ||||||
|  |  | ||||||
|             var applicant = mapper.Map<Applicant>(request); |         var applicant = mapper.Map<Applicant>(request); | ||||||
|             applicant.UserId = user.Id; |         applicant.UserId = user.Id; | ||||||
|  |  | ||||||
|             await users.AddAsync(user, cancellationToken); |         await users.AddAsync(user, cancellationToken); | ||||||
|             await applicants.AddAsync(applicant, cancellationToken); |         await applicants.AddAsync(applicant, cancellationToken); | ||||||
|  |  | ||||||
|             await unitOfWork.SaveAsync(cancellationToken); |         await unitOfWork.SaveAsync(cancellationToken); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         async Task IRegisterService.RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken) |     async Task IRegisterService.RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             var user = mapper.Map<User>(request.AuthData); |         var user = mapper.Map<User>(request.AuthData); | ||||||
|             user.Role = Role.ApprovingAuthority; |         user.Role = Role.ApprovingAuthority; | ||||||
|  |  | ||||||
|             await users.AddAsync(user, cancellationToken); |         await users.AddAsync(user, cancellationToken); | ||||||
|  |  | ||||||
|             await unitOfWork.SaveAsync(cancellationToken); |         await unitOfWork.SaveAsync(cancellationToken); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -2,22 +2,21 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.Common; | using ApplicationLayer.Services.AuthServices.Common; | ||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests | namespace ApplicationLayer.Services.AuthServices.Requests; | ||||||
| { |  | ||||||
|     public record RegisterApplicantRequest( | public record RegisterApplicantRequest( | ||||||
|         AuthData AuthData, |     AuthData AuthData, | ||||||
|         Name ApplicantName, |     Name ApplicantName, | ||||||
|         Passport Passport, |     Passport Passport, | ||||||
|         DateTime BirthDate, |     DateTime BirthDate, | ||||||
|         string CityOfBirth, |     string CityOfBirth, | ||||||
|         string CountryOfBirth, |     string CountryOfBirth, | ||||||
|         string Citizenship, |     string Citizenship, | ||||||
|         string CitizenshipByBirth, |     string CitizenshipByBirth, | ||||||
|         Gender Gender, |     Gender Gender, | ||||||
|         MaritalStatus MaritalStatus, |     MaritalStatus MaritalStatus, | ||||||
|         Name FatherName, |     Name FatherName, | ||||||
|         Name MotherName, |     Name MotherName, | ||||||
|         string JobTitle, |     string JobTitle, | ||||||
|         PlaceOfWorkModel PlaceOfWork, |     PlaceOfWorkModel PlaceOfWork, | ||||||
|         bool IsNonResident) : RegisterRequest(AuthData); |     bool IsNonResident) : RegisterRequest(AuthData); | ||||||
| } |  | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.Common; | using ApplicationLayer.Services.AuthServices.Common; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests | namespace ApplicationLayer.Services.AuthServices.Requests; | ||||||
| { |  | ||||||
|     public record RegisterRequest(AuthData AuthData); | public record RegisterRequest(AuthData AuthData); | ||||||
| } |  | ||||||
| @@ -3,12 +3,12 @@ using ApplicationLayer.Services.AuthServices.NeededServices; | |||||||
| using Domains; | using Domains; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | namespace ApplicationLayer.Services.AuthServices.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class AuthDataValidator : AbstractValidator<AuthData> | ||||||
| { | { | ||||||
|     public class AuthDataValidator : AbstractValidator<AuthData> |     public AuthDataValidator(IUsersRepository users) | ||||||
|     { |     { | ||||||
|         public AuthDataValidator(IUsersRepository users) |  | ||||||
|         { |  | ||||||
|             RuleFor(d => d.Email) |             RuleFor(d => d.Email) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Email can not be empty") |                 .WithMessage("Email can not be empty") | ||||||
| @@ -28,5 +28,4 @@ namespace ApplicationLayer.Services.AuthServices.Requests.Validation | |||||||
|                 .MaximumLength(ConfigurationConstraints.PasswordLength) |                 .MaximumLength(ConfigurationConstraints.PasswordLength) | ||||||
|                 .WithMessage($"Password length must be less than {ConfigurationConstraints.PasswordLength}"); |                 .WithMessage($"Password length must be less than {ConfigurationConstraints.PasswordLength}"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -2,12 +2,12 @@ | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | namespace ApplicationLayer.Services.AuthServices.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class NameValidator : AbstractValidator<Name> | ||||||
| { | { | ||||||
|     public class NameValidator : AbstractValidator<Name> |     public NameValidator() | ||||||
|     { |     { | ||||||
|         public NameValidator() |  | ||||||
|         { |  | ||||||
|             RuleFor(m => m.FirstName) |             RuleFor(m => m.FirstName) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("First Name can not be empty") |                 .WithMessage("First Name can not be empty") | ||||||
| @@ -24,5 +24,4 @@ namespace ApplicationLayer.Services.AuthServices.Requests.Validation | |||||||
|                 .MaximumLength(ConfigurationConstraints.NameLength) |                 .MaximumLength(ConfigurationConstraints.NameLength) | ||||||
|                 .WithMessage($"Patronymic length must be less than {ConfigurationConstraints.NameLength}"); |                 .WithMessage($"Patronymic length must be less than {ConfigurationConstraints.NameLength}"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -3,12 +3,12 @@ using Domains; | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | namespace ApplicationLayer.Services.AuthServices.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class PassportValidator : AbstractValidator<Passport> | ||||||
| { | { | ||||||
|     public class PassportValidator : AbstractValidator<Passport> |     public PassportValidator(IDateTimeProvider dateTimeProvider) | ||||||
|     { |     { | ||||||
|         public PassportValidator(IDateTimeProvider dateTimeProvider) |  | ||||||
|         { |  | ||||||
|             RuleFor(r => r.Issuer) |             RuleFor(r => r.Issuer) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Passport issuer can not be empty") |                 .WithMessage("Passport issuer can not be empty") | ||||||
| @@ -33,5 +33,4 @@ namespace ApplicationLayer.Services.AuthServices.Requests.Validation | |||||||
|                 .LessThanOrEqualTo(dateTimeProvider.Now()) |                 .LessThanOrEqualTo(dateTimeProvider.Now()) | ||||||
|                 .WithMessage("Passport issue date must be in past"); |                 .WithMessage("Passport issue date must be in past"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -2,12 +2,12 @@ | |||||||
| using Domains; | using Domains; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | namespace ApplicationLayer.Services.AuthServices.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class PlaceOfWorkModelValidator : AbstractValidator<PlaceOfWorkModel> | ||||||
| { | { | ||||||
|     public class PlaceOfWorkModelValidator : AbstractValidator<PlaceOfWorkModel> |     public PlaceOfWorkModelValidator() | ||||||
|     { |     { | ||||||
|         public PlaceOfWorkModelValidator() |  | ||||||
|         { |  | ||||||
|             RuleFor(p => p.Name) |             RuleFor(p => p.Name) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Place of work name can not be empty") |                 .WithMessage("Place of work name can not be empty") | ||||||
| @@ -46,5 +46,4 @@ namespace ApplicationLayer.Services.AuthServices.Requests.Validation | |||||||
|                 .MaximumLength(ConfigurationConstraints.CountryNameLength) |                 .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||||
|                 .WithMessage($"Building of place of work length must be less than {ConfigurationConstraints.BuildingNumberLength}"); |                 .WithMessage($"Building of place of work length must be less than {ConfigurationConstraints.BuildingNumberLength}"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -5,17 +5,17 @@ using Domains; | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests.Validation | namespace ApplicationLayer.Services.AuthServices.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class RegisterApplicantRequestValidator : AbstractValidator<RegisterApplicantRequest> | ||||||
| { | { | ||||||
|     public class RegisterApplicantRequestValidator : AbstractValidator<RegisterApplicantRequest> |     public RegisterApplicantRequestValidator( | ||||||
|  |         IDateTimeProvider dateTimeProvider, | ||||||
|  |         IValidator<Name> nameValidator, | ||||||
|  |         IValidator<AuthData> authDataValidator, | ||||||
|  |         IValidator<Passport> passportValidator, | ||||||
|  |         IValidator<PlaceOfWorkModel> placeOfWorkModelValidator) | ||||||
|     { |     { | ||||||
|         public RegisterApplicantRequestValidator( |  | ||||||
|             IDateTimeProvider dateTimeProvider, |  | ||||||
|             IValidator<Name> nameValidator, |  | ||||||
|             IValidator<AuthData> authDataValidator, |  | ||||||
|             IValidator<Passport> passportValidator, |  | ||||||
|             IValidator<PlaceOfWorkModel> placeOfWorkModelValidator) |  | ||||||
|         { |  | ||||||
|             RuleFor(r => r.AuthData) |             RuleFor(r => r.AuthData) | ||||||
|                 .SetValidator(authDataValidator); |                 .SetValidator(authDataValidator); | ||||||
|  |  | ||||||
| @@ -74,5 +74,4 @@ namespace ApplicationLayer.Services.AuthServices.Requests.Validation | |||||||
|             RuleFor(r => r.PlaceOfWork) |             RuleFor(r => r.PlaceOfWork) | ||||||
|                 .SetValidator(placeOfWorkModelValidator); |                 .SetValidator(placeOfWorkModelValidator); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,23 +1,22 @@ | |||||||
| using ApplicationLayer.Services.Users.Requests; | using ApplicationLayer.Services.Users.Requests; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Users | namespace ApplicationLayer.Services.Users; | ||||||
|  |  | ||||||
|  | /// user accounts service | ||||||
|  | public interface IUsersService | ||||||
| { | { | ||||||
|     /// user accounts service |     /// Returns all user accounts with role of approving authority | ||||||
|     public interface IUsersService |     /// <param name="cancellationToken">Cancellation token</param> | ||||||
|     { |     Task<List<User>> GetAuthoritiesAccountsAsync(CancellationToken cancellationToken); | ||||||
|         /// Returns all user accounts with role of approving authority |  | ||||||
|         /// <param name="cancellationToken">Cancellation token</param> |  | ||||||
|         Task<List<User>> GetAuthoritiesAccountsAsync(CancellationToken cancellationToken); |  | ||||||
|  |  | ||||||
|         /// Changes authentication data for an account |     /// Changes authentication data for an account | ||||||
|         /// <param name="request"> Request object with identifier of user and new authentication data</param> |     /// <param name="request"> Request object with identifier of user and new authentication data</param> | ||||||
|         /// <param name="cancellationToken">Cancellation token</param> |     /// <param name="cancellationToken">Cancellation token</param> | ||||||
|         Task ChangeAccountAuthDataAsync(ChangeUserAuthDataRequest request, CancellationToken cancellationToken); |     Task ChangeAccountAuthDataAsync(ChangeUserAuthDataRequest request, CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|         /// Removes user account |     /// Removes user account | ||||||
|         /// <param name="userId">Identifier of account</param> |     /// <param name="userId">Identifier of account</param> | ||||||
|         /// <param name="cancellationToken">Cancellation token</param> |     /// <param name="cancellationToken">Cancellation token</param> | ||||||
|         Task RemoveUserAccount(Guid userId, CancellationToken cancellationToken); |     Task RemoveUserAccount(Guid userId, CancellationToken cancellationToken); | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.Common; | using ApplicationLayer.Services.AuthServices.Common; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Users.Requests | namespace ApplicationLayer.Services.Users.Requests; | ||||||
| { |  | ||||||
|     public record ChangeUserAuthDataRequest(Guid UserId, AuthData NewAuthData); | public record ChangeUserAuthDataRequest(Guid UserId, AuthData NewAuthData); | ||||||
| } |  | ||||||
| @@ -3,17 +3,17 @@ using ApplicationLayer.Services.AuthServices.NeededServices; | |||||||
| using ApplicationLayer.Services.Users.Requests; | using ApplicationLayer.Services.Users.Requests; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Users | namespace ApplicationLayer.Services.Users; | ||||||
|  |  | ||||||
|  | public class UsersService(IUsersRepository users, IUnitOfWork unitOfWork) : IUsersService | ||||||
| { | { | ||||||
|     public class UsersService(IUsersRepository users, IUnitOfWork unitOfWork) : IUsersService |     async Task<List<User>> IUsersService.GetAuthoritiesAccountsAsync(CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         async Task<List<User>> IUsersService.GetAuthoritiesAccountsAsync(CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             return await users.GetAllOfRoleAsync(Role.ApprovingAuthority, cancellationToken); |             return await users.GetAllOfRoleAsync(Role.ApprovingAuthority, cancellationToken); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         async Task IUsersService.ChangeAccountAuthDataAsync(ChangeUserAuthDataRequest request, CancellationToken cancellationToken) |     async Task IUsersService.ChangeAccountAuthDataAsync(ChangeUserAuthDataRequest request, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             var user = await users.GetByIdAsync(request.UserId, cancellationToken); |             var user = await users.GetByIdAsync(request.UserId, cancellationToken); | ||||||
|  |  | ||||||
|             user.Email = request.NewAuthData.Email; |             user.Email = request.NewAuthData.Email; | ||||||
| @@ -23,12 +23,11 @@ namespace ApplicationLayer.Services.Users | |||||||
|             await unitOfWork.SaveAsync(cancellationToken); |             await unitOfWork.SaveAsync(cancellationToken); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         async Task IUsersService.RemoveUserAccount(Guid userId, CancellationToken cancellationToken) |     async Task IUsersService.RemoveUserAccount(Guid userId, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             var user = await users.GetByIdAsync(userId, cancellationToken); |             var user = await users.GetByIdAsync(userId, cancellationToken); | ||||||
|             users.Remove(user); |             users.Remove(user); | ||||||
|  |  | ||||||
|             await unitOfWork.SaveAsync(cancellationToken); |             await unitOfWork.SaveAsync(cancellationToken); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| using ApplicationLayer.GeneralExceptions; | using ApplicationLayer.GeneralExceptions; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Exceptions | namespace ApplicationLayer.Services.VisaApplications.Exceptions; | ||||||
| { |  | ||||||
|     public class ApplicationAlreadyProcessedException() : ApiException("This application already processed or closed by applicant."); | public class ApplicationAlreadyProcessedException() : ApiException("This application already processed or closed by applicant."); | ||||||
| } |  | ||||||
| @@ -9,13 +9,13 @@ public interface IVisaApplicationRequestsHandler | |||||||
|     Task<List<VisaApplicationModelForAuthority>> GetAllAsync(CancellationToken cancellationToken); |     Task<List<VisaApplicationModelForAuthority>> GetAllAsync(CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|     /// Returns all applications of one applicant |     /// Returns all applications of one applicant | ||||||
|     Task<List<VisaApplicationModelForApplicant>> GetForApplicantAsync(Guid userId, CancellationToken cancellationToken); |     Task<List<VisaApplicationModelForApplicant>> GetForApplicantAsync(CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|     /// Creates application for applicant with specific user identifier |     /// Creates application for applicant with specific user identifier | ||||||
|     Task HandleCreateRequestAsync(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken); |     Task HandleCreateRequestAsync(VisaApplicationCreateRequest request, CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|     /// Sets application status to closed |     /// Sets application status to closed | ||||||
|     Task HandleCloseRequestAsync(Guid userId, Guid applicationId, CancellationToken cancellationToken); |     Task HandleCloseRequestAsync(Guid applicationId, CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|     Task SetApplicationStatusFromAuthorityAsync(Guid applicationId, AuthorityRequestStatuses status, CancellationToken cancellationToken); |     Task SetApplicationStatusFromAuthorityAsync(Guid applicationId, AuthorityRequestStatuses status, CancellationToken cancellationToken); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,7 +16,8 @@ public class VisaApplicationRequestsHandler( | |||||||
|     IApplicantsRepository applicants, |     IApplicantsRepository applicants, | ||||||
|     IUnitOfWork unitOfWork, |     IUnitOfWork unitOfWork, | ||||||
|     IMapper mapper, |     IMapper mapper, | ||||||
|     IDateTimeProvider dateTimeProvider) : IVisaApplicationRequestsHandler |     IDateTimeProvider dateTimeProvider, | ||||||
|  |     IUserIdProvider userIdProvider) : IVisaApplicationRequestsHandler | ||||||
| { | { | ||||||
|     async Task<List<VisaApplicationModelForAuthority>> IVisaApplicationRequestsHandler.GetAllAsync(CancellationToken cancellationToken) |     async Task<List<VisaApplicationModelForAuthority>> IVisaApplicationRequestsHandler.GetAllAsync(CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
| @@ -40,16 +41,16 @@ public class VisaApplicationRequestsHandler( | |||||||
|         return model; |         return model; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public async Task<List<VisaApplicationModelForApplicant>> GetForApplicantAsync(Guid userId, CancellationToken cancellationToken) |     public async Task<List<VisaApplicationModelForApplicant>> GetForApplicantAsync(CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         var applicantId = await applicants.GetApplicantIdByUserId(userId, cancellationToken); |         var applicantId = await applicants.GetApplicantIdByUserId(userIdProvider.GetUserId(), cancellationToken); | ||||||
|         var visaApplications = await applications.GetOfApplicantAsync(applicantId, cancellationToken); |         var visaApplications = await applications.GetOfApplicantAsync(applicantId, cancellationToken); | ||||||
|         return mapper.Map<List<VisaApplicationModelForApplicant>>(visaApplications); |         return mapper.Map<List<VisaApplicationModelForApplicant>>(visaApplications); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public async Task HandleCreateRequestAsync(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken) |     public async Task HandleCreateRequestAsync(VisaApplicationCreateRequest request, CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         var applicant = await applicants.FindByUserIdAsync(userId, cancellationToken); |         var applicant = await applicants.FindByUserIdAsync(userIdProvider.GetUserId(), cancellationToken); | ||||||
|  |  | ||||||
|         var visaApplication = mapper.Map<VisaApplication>(request); |         var visaApplication = mapper.Map<VisaApplication>(request); | ||||||
|         visaApplication.RequestDate = dateTimeProvider.Now(); |         visaApplication.RequestDate = dateTimeProvider.Now(); | ||||||
| @@ -60,9 +61,9 @@ public class VisaApplicationRequestsHandler( | |||||||
|         await unitOfWork.SaveAsync(cancellationToken); |         await unitOfWork.SaveAsync(cancellationToken); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async Task IVisaApplicationRequestsHandler.HandleCloseRequestAsync(Guid userId, Guid applicationId, CancellationToken cancellationToken) |     async Task IVisaApplicationRequestsHandler.HandleCloseRequestAsync(Guid applicationId, CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         var applicantId = await applicants.GetApplicantIdByUserId(userId, cancellationToken); |         var applicantId = await applicants.GetApplicantIdByUserId(userIdProvider.GetUserId(), cancellationToken); | ||||||
|         var application = await applications.GetByApplicantAndApplicationIdAsync(applicantId, applicationId, cancellationToken); |         var application = await applications.GetByApplicantAndApplicationIdAsync(applicantId, applicationId, cancellationToken); | ||||||
|  |  | ||||||
|         application.Status = ApplicationStatus.Closed; |         application.Status = ApplicationStatus.Closed; | ||||||
|   | |||||||
| @@ -1,8 +1,7 @@ | |||||||
| namespace ApplicationLayer.Services.VisaApplications.Models | namespace ApplicationLayer.Services.VisaApplications.Models; | ||||||
|  |  | ||||||
|  | public enum AuthorityRequestStatuses | ||||||
| { | { | ||||||
|     public enum AuthorityRequestStatuses |     Approved, | ||||||
|     { |     Rejected | ||||||
|         Approved, |  | ||||||
|         Rejected |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,44 +1,43 @@ | |||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Models | namespace ApplicationLayer.Services.VisaApplications.Models; | ||||||
|  |  | ||||||
|  | /// Model of <see cref="VisaApplication"/> | ||||||
|  | public class VisaApplicationModelForApplicant | ||||||
| { | { | ||||||
|     /// Model of <see cref="VisaApplication"/> |     /// <inheritdoc cref="VisaApplication.Id"/> | ||||||
|     public class VisaApplicationModelForApplicant |     public Guid Id { get; set; } | ||||||
|     { |  | ||||||
|         /// <inheritdoc cref="VisaApplication.Id"/> |  | ||||||
|         public Guid Id { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.Status"/> |     /// <inheritdoc cref="VisaApplication.Status"/> | ||||||
|         public ApplicationStatus Status { get; set; } |     public ApplicationStatus Status { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.ReentryPermit"/> |     /// <inheritdoc cref="VisaApplication.ReentryPermit"/> | ||||||
|         public ReentryPermit? ReentryPermit { get; set; } |     public ReentryPermit? ReentryPermit { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.DestinationCountry"/> |     /// <inheritdoc cref="VisaApplication.DestinationCountry"/> | ||||||
|         public string DestinationCountry { get; set; } = null!; |     public string DestinationCountry { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.PastVisas"/> |     /// <inheritdoc cref="VisaApplication.PastVisas"/> | ||||||
|         public List<PastVisa> PastVisas { get; set; } = null!; |     public List<PastVisa> PastVisas { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/> |     /// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/> | ||||||
|         public PermissionToDestCountry? PermissionToDestCountry { get; set; } |     public PermissionToDestCountry? PermissionToDestCountry { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.PastVisits"/> |     /// <inheritdoc cref="VisaApplication.PastVisits"/> | ||||||
|         public List<PastVisit> PastVisits { get; set; } = null!; |     public List<PastVisit> PastVisits { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.VisaCategory"/> |     /// <inheritdoc cref="VisaApplication.VisaCategory"/> | ||||||
|         public VisaCategory VisaCategory { get; set; } |     public VisaCategory VisaCategory { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.ForGroup"/> |     /// <inheritdoc cref="VisaApplication.ForGroup"/> | ||||||
|         public bool ForGroup { get; set; } |     public bool ForGroup { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.RequestedNumberOfEntries"/> |     /// <inheritdoc cref="VisaApplication.RequestedNumberOfEntries"/> | ||||||
|         public RequestedNumberOfEntries RequestedNumberOfEntries { get; set; } |     public RequestedNumberOfEntries RequestedNumberOfEntries { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.RequestDate"/> |     /// <inheritdoc cref="VisaApplication.RequestDate"/> | ||||||
|         public DateTime RequestDate { get; set; } |     public DateTime RequestDate { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.ValidDaysRequested"/> |     /// <inheritdoc cref="VisaApplication.ValidDaysRequested"/> | ||||||
|         public int ValidDaysRequested { get; set; } |     public int ValidDaysRequested { get; set; } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,47 +1,46 @@ | |||||||
| using ApplicationLayer.Services.Applicants.Models; | using ApplicationLayer.Services.Applicants.Models; | ||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Models | namespace ApplicationLayer.Services.VisaApplications.Models; | ||||||
|  |  | ||||||
|  | /// Model of <see cref="VisaApplication"/> with applicant property | ||||||
|  | public class VisaApplicationModelForAuthority | ||||||
| { | { | ||||||
|     /// Model of <see cref="VisaApplication"/> with applicant property |     /// <inheritdoc cref="VisaApplication.Id"/> | ||||||
|     public class VisaApplicationModelForAuthority |     public Guid Id { get; set; } | ||||||
|     { |  | ||||||
|         /// <inheritdoc cref="VisaApplication.Id"/> |  | ||||||
|         public Guid Id { get; set; } |  | ||||||
|  |  | ||||||
|         /// Applicant of application |     /// Applicant of application | ||||||
|         public ApplicantModel Applicant { get; set; } = null!; |     public ApplicantModel Applicant { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.Status"/> |     /// <inheritdoc cref="VisaApplication.Status"/> | ||||||
|         public ApplicationStatus Status { get; set; } |     public ApplicationStatus Status { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.ReentryPermit"/> |     /// <inheritdoc cref="VisaApplication.ReentryPermit"/> | ||||||
|         public ReentryPermit? ReentryPermit { get; set; } |     public ReentryPermit? ReentryPermit { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.DestinationCountry"/> |     /// <inheritdoc cref="VisaApplication.DestinationCountry"/> | ||||||
|         public string DestinationCountry { get; set; } = null!; |     public string DestinationCountry { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.PastVisas"/> |     /// <inheritdoc cref="VisaApplication.PastVisas"/> | ||||||
|         public List<PastVisa> PastVisas { get; set; } = null!; |     public List<PastVisa> PastVisas { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/> |     /// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/> | ||||||
|         public PermissionToDestCountry? PermissionToDestCountry { get; set; } |     public PermissionToDestCountry? PermissionToDestCountry { get; set; } | ||||||
|  |  | ||||||
|         public List<PastVisit> PastVisits { get; set; } = null!; |     public List<PastVisit> PastVisits { get; set; } = null!; | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.VisaCategory"/> |     /// <inheritdoc cref="VisaApplication.VisaCategory"/> | ||||||
|         public VisaCategory VisaCategory { get; set; } |     public VisaCategory VisaCategory { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.ForGroup"/> |     /// <inheritdoc cref="VisaApplication.ForGroup"/> | ||||||
|         public bool ForGroup { get; set; } |     public bool ForGroup { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.RequestedNumberOfEntries"/> |     /// <inheritdoc cref="VisaApplication.RequestedNumberOfEntries"/> | ||||||
|         public RequestedNumberOfEntries RequestedNumberOfEntries { get; set; } |     public RequestedNumberOfEntries RequestedNumberOfEntries { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.RequestDate"/> |     /// <inheritdoc cref="VisaApplication.RequestDate"/> | ||||||
|         public DateTime RequestDate { get; set; } |     public DateTime RequestDate { get; set; } | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="VisaApplication.ValidDaysRequested"/> |     /// <inheritdoc cref="VisaApplication.ValidDaysRequested"/> | ||||||
|         public int ValidDaysRequested { get; set; } |     public int ValidDaysRequested { get; set; } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -2,12 +2,12 @@ | |||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | namespace ApplicationLayer.Services.VisaApplications.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class PastVisaValidator : AbstractValidator<PastVisa> | ||||||
| { | { | ||||||
|     public class PastVisaValidator : AbstractValidator<PastVisa> |     public PastVisaValidator(IDateTimeProvider dateTimeProvider) | ||||||
|     { |     { | ||||||
|         public PastVisaValidator(IDateTimeProvider dateTimeProvider) |  | ||||||
|         { |  | ||||||
|             RuleFor(v => v.ExpirationDate) |             RuleFor(v => v.ExpirationDate) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Expiration date of past visa can not be empty") |                 .WithMessage("Expiration date of past visa can not be empty") | ||||||
| @@ -24,5 +24,4 @@ namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | |||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Name of past visa can not be empty"); |                 .WithMessage("Name of past visa can not be empty"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -3,12 +3,12 @@ using Domains; | |||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | namespace ApplicationLayer.Services.VisaApplications.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class PastVisitValidator : AbstractValidator<PastVisit> | ||||||
| { | { | ||||||
|     public class PastVisitValidator : AbstractValidator<PastVisit> |     public PastVisitValidator(IDateTimeProvider dateTimeProvider) | ||||||
|     { |     { | ||||||
|         public PastVisitValidator(IDateTimeProvider dateTimeProvider) |  | ||||||
|         { |  | ||||||
|             RuleFor(v => v.StartDate) |             RuleFor(v => v.StartDate) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Start date of past visit can not be empty") |                 .WithMessage("Start date of past visit can not be empty") | ||||||
| @@ -27,5 +27,4 @@ namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | |||||||
|                 .MaximumLength(ConfigurationConstraints.CountryNameLength) |                 .MaximumLength(ConfigurationConstraints.CountryNameLength) | ||||||
|                 .WithMessage($"Destination Country of past visit length must be less than {ConfigurationConstraints.CountryNameLength}"); |                 .WithMessage($"Destination Country of past visit length must be less than {ConfigurationConstraints.CountryNameLength}"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -3,12 +3,12 @@ using Domains; | |||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | namespace ApplicationLayer.Services.VisaApplications.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class PermissionToDestCountryValidator : AbstractValidator<PermissionToDestCountry?> | ||||||
| { | { | ||||||
|     public class PermissionToDestCountryValidator : AbstractValidator<PermissionToDestCountry?> |     public PermissionToDestCountryValidator(IDateTimeProvider dateTimeProvider) | ||||||
|     { |     { | ||||||
|         public PermissionToDestCountryValidator(IDateTimeProvider dateTimeProvider) |  | ||||||
|         { |  | ||||||
|             RuleFor(p => p!.ExpirationDate) |             RuleFor(p => p!.ExpirationDate) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Expiration date of permission to destination Country can not be empty") |                 .WithMessage("Expiration date of permission to destination Country can not be empty") | ||||||
| @@ -21,5 +21,4 @@ namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | |||||||
|                 .MaximumLength(ConfigurationConstraints.IssuerNameLength) |                 .MaximumLength(ConfigurationConstraints.IssuerNameLength) | ||||||
|                 .WithMessage($"Issuer of permission to destination Country length must be less than {ConfigurationConstraints.IssuerNameLength}"); |                 .WithMessage($"Issuer of permission to destination Country length must be less than {ConfigurationConstraints.IssuerNameLength}"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -3,12 +3,12 @@ using Domains; | |||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | namespace ApplicationLayer.Services.VisaApplications.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class ReentryPermitValidator : AbstractValidator<ReentryPermit?> | ||||||
| { | { | ||||||
|     public class ReentryPermitValidator : AbstractValidator<ReentryPermit?> |     public ReentryPermitValidator(IDateTimeProvider dateTimeProvider) | ||||||
|     { |     { | ||||||
|         public ReentryPermitValidator(IDateTimeProvider dateTimeProvider) |  | ||||||
|         { |  | ||||||
|             RuleFor(p => p!.Number) |             RuleFor(p => p!.Number) | ||||||
|                 .NotEmpty() |                 .NotEmpty() | ||||||
|                 .WithMessage("Re-entry permit number can not be empty") |                 .WithMessage("Re-entry permit number can not be empty") | ||||||
| @@ -21,5 +21,4 @@ namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | |||||||
|                 .GreaterThan(dateTimeProvider.Now()) |                 .GreaterThan(dateTimeProvider.Now()) | ||||||
|                 .WithMessage("Re-entry permit must not be expired"); |                 .WithMessage("Re-entry permit must not be expired"); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -4,51 +4,50 @@ using Domains; | |||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using FluentValidation; | using FluentValidation; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Requests.Validation | namespace ApplicationLayer.Services.VisaApplications.Requests.Validation; | ||||||
|  |  | ||||||
|  | public class VisaApplicationCreateRequestValidator : AbstractValidator<VisaApplicationCreateRequest> | ||||||
| { | { | ||||||
|     public class VisaApplicationCreateRequestValidator : AbstractValidator<VisaApplicationCreateRequest> |     public VisaApplicationCreateRequestValidator( | ||||||
|  |         IValidator<ReentryPermit?> reentryPermitValidator, | ||||||
|  |         IValidator<PastVisa> pastVisaValidator, | ||||||
|  |         IValidator<PermissionToDestCountry?> permissionToDestCountryValidator, | ||||||
|  |         IValidator<PastVisit> pastVisitValidator, | ||||||
|  |         IApplicantsRepository applicants, | ||||||
|  |         IUserIdProvider userIdProvider) | ||||||
|     { |     { | ||||||
|         public VisaApplicationCreateRequestValidator( |         RuleFor(r => r.ReentryPermit) | ||||||
|             IValidator<ReentryPermit?> reentryPermitValidator, |             .NotEmpty() | ||||||
|             IValidator<PastVisa> pastVisaValidator, |             .WithMessage("Non-residents must provide re-entry permission") | ||||||
|             IValidator<PermissionToDestCountry?> permissionToDestCountryValidator, |             .SetValidator(reentryPermitValidator) | ||||||
|             IValidator<PastVisit> pastVisitValidator, |             .WhenAsync(async (_, ct) => | ||||||
|             IApplicantsRepository applicants, |                 await applicants.IsApplicantNonResidentByUserId(userIdProvider.GetUserId(), ct)); | ||||||
|             IUserIdProvider userIdProvider) |  | ||||||
|         { |  | ||||||
|             RuleFor(r => r.ReentryPermit) |  | ||||||
|                 .NotEmpty() |  | ||||||
|                 .WithMessage("Non-residents must provide re-entry permission") |  | ||||||
|                 .SetValidator(reentryPermitValidator) |  | ||||||
|                 .WhenAsync(async (r, ct) => |  | ||||||
|                     await applicants.IsApplicantNonResidentByUserId(userIdProvider.GetUserId(), ct)); |  | ||||||
|  |  | ||||||
|             RuleFor(r => r.DestinationCountry) |         RuleFor(r => r.DestinationCountry) | ||||||
|                 .NotEmpty() |             .NotEmpty() | ||||||
|                 .WithMessage("Destination country can not be empty"); |             .WithMessage("Destination country can not be empty"); | ||||||
|  |  | ||||||
|             RuleFor(r => r.VisaCategory) |         RuleFor(r => r.VisaCategory) | ||||||
|                 .IsInEnum(); |             .IsInEnum(); | ||||||
|  |  | ||||||
|             RuleFor(r => r.RequestedNumberOfEntries) |         RuleFor(r => r.RequestedNumberOfEntries) | ||||||
|                 .IsInEnum(); |             .IsInEnum(); | ||||||
|  |  | ||||||
|             RuleFor(r => r.ValidDaysRequested) |         RuleFor(r => r.ValidDaysRequested) | ||||||
|                 .GreaterThan(0) |             .GreaterThan(0) | ||||||
|                 .WithMessage($"Valid days requested should be positive number and less than {ConfigurationConstraints.MaxValidDays}") |             .WithMessage($"Valid days requested should be positive number and less than {ConfigurationConstraints.MaxValidDays}") | ||||||
|                 .LessThanOrEqualTo(ConfigurationConstraints.MaxValidDays) |             .LessThanOrEqualTo(ConfigurationConstraints.MaxValidDays) | ||||||
|                 .WithMessage($"Valid days requested must be less than or equal to {ConfigurationConstraints.MaxValidDays}"); |             .WithMessage($"Valid days requested must be less than or equal to {ConfigurationConstraints.MaxValidDays}"); | ||||||
|  |  | ||||||
|             RuleForEach(r => r.PastVisas) |         RuleForEach(r => r.PastVisas) | ||||||
|                 .SetValidator(pastVisaValidator); |             .SetValidator(pastVisaValidator); | ||||||
|  |  | ||||||
|             When(r => r.VisaCategory == VisaCategory.Transit, |         When(r => r.VisaCategory == VisaCategory.Transit, | ||||||
|                 () => |             () => | ||||||
|                     RuleFor(r => r.PermissionToDestCountry) |                 RuleFor(r => r.PermissionToDestCountry) | ||||||
|                         .SetValidator(permissionToDestCountryValidator)); |                     .SetValidator(permissionToDestCountryValidator)); | ||||||
|  |  | ||||||
|             RuleForEach(r => r.PastVisits) |         RuleForEach(r => r.PastVisits) | ||||||
|                 .SetValidator(pastVisitValidator); |             .SetValidator(pastVisitValidator); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,24 +1,23 @@ | |||||||
| namespace Domains | namespace Domains; | ||||||
|  |  | ||||||
|  | public static class ConfigurationConstraints | ||||||
| { | { | ||||||
|     public static class ConfigurationConstraints |     public const int CityNameLength = 70; | ||||||
|     { |     public const int CountryNameLength = 70; | ||||||
|         public const int CityNameLength = 70; |     public const int CitizenshipLength = 30; | ||||||
|         public const int CountryNameLength = 70; |     public const int ReentryPermitNumberLength = 25; | ||||||
|         public const int CitizenshipLength = 30; |     public const int IssuerNameLength = 200; | ||||||
|         public const int ReentryPermitNumberLength = 25; |     public const int VisaNameLength = 70; | ||||||
|         public const int IssuerNameLength = 200; |     public const int StreetNameLength = 100; | ||||||
|         public const int VisaNameLength = 70; |     public const int PlaceOfWorkNameLength = 200; | ||||||
|         public const int StreetNameLength = 100; |     public const int NameLength = 50; | ||||||
|         public const int PlaceOfWorkNameLength = 200; |     public const int BuildingNumberLength = 10; | ||||||
|         public const int NameLength = 50; |     public const int PassportNumberLength = 20; | ||||||
|         public const int BuildingNumberLength = 10; |     public const int PhoneNumberLength = 13; | ||||||
|         public const int PassportNumberLength = 20; |     public const int PhoneNumberMinLength = 11; | ||||||
|         public const int PhoneNumberLength = 13; |     public const int EmailLength = 254; | ||||||
|         public const int PhoneNumberMinLength = 11; |     public const int PasswordLength = 50; | ||||||
|         public const int EmailLength = 254; |     public const int ApplicantMinAge = 14; | ||||||
|         public const int PasswordLength = 50; |     public const int JobTitleLength = 50; | ||||||
|         public const int ApplicantMinAge = 14; |     public const int MaxValidDays = 90; | ||||||
|         public const int JobTitleLength = 50; |  | ||||||
|         public const int MaxValidDays = 90; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,13 +1,12 @@ | |||||||
| namespace Domains.Users | namespace Domains.Users; | ||||||
|  |  | ||||||
|  | /// Role of <see cref="User"/> | ||||||
|  | public enum Role | ||||||
| { | { | ||||||
|     /// Role of <see cref="User"/> |     /// Requests visa applications | ||||||
|     public enum Role |     Applicant, | ||||||
|     { |     /// Approves or declines applications | ||||||
|         /// Requests visa applications |     ApprovingAuthority, | ||||||
|         Applicant, |     /// Manages approving authorities | ||||||
|         /// Approves or declines applications |     Admin | ||||||
|         ApprovingAuthority, |  | ||||||
|         /// Manages approving authorities |  | ||||||
|         Admin |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,14 +1,13 @@ | |||||||
| namespace Domains.Users | namespace Domains.Users; | ||||||
|  |  | ||||||
|  | public class User : IEntity | ||||||
| { | { | ||||||
|     public class User : IEntity |     /// Unique Identifier of <see cref="User"/> | ||||||
|     { |     public Guid Id { get; private set; } = Guid.NewGuid(); | ||||||
|         /// Unique Identifier of <see cref="User"/> |  | ||||||
|         public Guid Id { get; private set; } = Guid.NewGuid(); |  | ||||||
|  |  | ||||||
|         public Role Role { get; set; } |     public Role Role { get; set; } | ||||||
|  |  | ||||||
|         public string Email { get; set; } = null!; |     public string Email { get; set; } = null!; | ||||||
|  |  | ||||||
|         public string Password { get; set; } = null!; |     public string Password { get; set; } = null!; | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,12 +1,11 @@ | |||||||
| namespace Domains.VisaApplicationDomain | namespace Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
|  | public enum ApplicationStatus | ||||||
| { | { | ||||||
|     public enum ApplicationStatus |     /// Waits for approve | ||||||
|     { |     Pending, | ||||||
|         /// Waits for approve |     Approved, | ||||||
|         Pending, |     Rejected, | ||||||
|         Approved, |     /// Closed by applicant | ||||||
|         Rejected, |     Closed | ||||||
|         /// Closed by applicant |  | ||||||
|         Closed |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -3,12 +3,12 @@ using ApplicationLayer.InfrastructureServicesInterfaces; | |||||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | using ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| 
 | 
 | ||||||
| namespace Infrastructure.Auth | namespace Infrastructure.Auth; | ||||||
|  | 
 | ||||||
|  | public static class ServiceCollectionExtensions | ||||||
| { | { | ||||||
|     public static class ServiceCollectionsExtensions |     public static IServiceCollection AddTokenGenerator(this IServiceCollection services, TokenGeneratorOptions options) | ||||||
|     { |     { | ||||||
|         public static IServiceCollection AddTokenGenerator(this IServiceCollection services, TokenGeneratorOptions options) |  | ||||||
|         { |  | ||||||
|             services.AddSingleton<JwtSecurityTokenHandler>(); |             services.AddSingleton<JwtSecurityTokenHandler>(); | ||||||
|             services.AddSingleton<ITokenGenerator, TokenGenerator>(provider => |             services.AddSingleton<ITokenGenerator, TokenGenerator>(provider => | ||||||
|             { |             { | ||||||
| @@ -20,5 +20,4 @@ namespace Infrastructure.Auth | |||||||
| 
 | 
 | ||||||
|             return services; |             return services; | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -4,27 +4,31 @@ using ApplicationLayer.InfrastructureServicesInterfaces; | |||||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | using ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace Infrastructure.Auth | namespace Infrastructure.Auth; | ||||||
|  |  | ||||||
|  | /// <inheritdoc cref="ITokenGenerator"/> | ||||||
|  | /// <param name="options">options kind of one in authorization registration in DI methods</param> | ||||||
|  | /// <param name="tokenHandler">token handler</param> | ||||||
|  | /// <param name="dateTimeProvider">date time provider</param> | ||||||
|  | public class TokenGenerator(TokenGeneratorOptions options, JwtSecurityTokenHandler tokenHandler, IDateTimeProvider dateTimeProvider) | ||||||
|  |     : ITokenGenerator | ||||||
| { | { | ||||||
|     public class TokenGenerator(TokenGeneratorOptions options, JwtSecurityTokenHandler tokenHandler, IDateTimeProvider dateTimeProvider) |     /// <inheritdoc cref="ITokenGenerator.CreateToken"/> | ||||||
|         : ITokenGenerator |     public string CreateToken(User user) | ||||||
|     { |     { | ||||||
|         public string CreateToken(User user) |         var claims = new List<Claim> | ||||||
|         { |         { | ||||||
|             var claims = new List<Claim> |             new(ClaimTypes.Role, user.Role.ToString()), | ||||||
|             { |             new(ClaimTypes.NameIdentifier, user.Id.ToString()) | ||||||
|                 new(ClaimTypes.Role, user.Role.ToString()), |         }; | ||||||
|                 new(ClaimTypes.NameIdentifier, user.Id.ToString()) |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             var token = new JwtSecurityToken( |         var token = new JwtSecurityToken( | ||||||
|                 issuer: options.Issuer, |             issuer: options.Issuer, | ||||||
|                 audience: options.Audience, |             audience: options.Audience, | ||||||
|                 expires: dateTimeProvider.Now().Add(options.ValidTime), |             expires: dateTimeProvider.Now().Add(options.ValidTime), | ||||||
|                 signingCredentials: options.Credentials, |             signingCredentials: options.Credentials, | ||||||
|                 claims: claims); |             claims: claims); | ||||||
|  |  | ||||||
|             return tokenHandler.WriteToken(token); |         return tokenHandler.WriteToken(token); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| using Microsoft.IdentityModel.Tokens; | using Microsoft.IdentityModel.Tokens; | ||||||
|  |  | ||||||
| namespace Infrastructure.Auth | namespace Infrastructure.Auth; | ||||||
| { |  | ||||||
|     public record TokenGeneratorOptions(string Issuer, string Audience, TimeSpan ValidTime, SigningCredentials Credentials); | public record TokenGeneratorOptions(string Issuer, string Audience, TimeSpan ValidTime, SigningCredentials Credentials); | ||||||
| } |  | ||||||
| @@ -3,12 +3,12 @@ using ApplicationLayer.Services.AuthServices.Requests; | |||||||
| using AutoMapper; | using AutoMapper; | ||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
|  |  | ||||||
| namespace Infrastructure.Automapper.Profiles | namespace Infrastructure.Automapper.Profiles; | ||||||
|  |  | ||||||
|  | public class ApplicantProfile : Profile | ||||||
| { | { | ||||||
|     public class ApplicantProfile : Profile |     public ApplicantProfile() | ||||||
|     { |     { | ||||||
|         public ApplicantProfile() |  | ||||||
|         { |  | ||||||
|             CreateMap<Applicant, ApplicantModel>(MemberList.Destination); |             CreateMap<Applicant, ApplicantModel>(MemberList.Destination); | ||||||
|  |  | ||||||
|             CreateMap<RegisterApplicantRequest, Applicant>(MemberList.Destination) |             CreateMap<RegisterApplicantRequest, Applicant>(MemberList.Destination) | ||||||
| @@ -16,5 +16,4 @@ namespace Infrastructure.Automapper.Profiles | |||||||
|                 .ForMember(a => a.Name, |                 .ForMember(a => a.Name, | ||||||
|                     opts => opts.MapFrom(r => r.ApplicantName)); |                     opts => opts.MapFrom(r => r.ApplicantName)); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -2,15 +2,14 @@ | |||||||
| using AutoMapper; | using AutoMapper; | ||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
|  |  | ||||||
| namespace Infrastructure.Automapper.Profiles | namespace Infrastructure.Automapper.Profiles; | ||||||
|  |  | ||||||
|  | public class PlaceOfWorkProfile : Profile | ||||||
| { | { | ||||||
|     public class PlaceOfWorkProfile : Profile |     public PlaceOfWorkProfile() | ||||||
|     { |     { | ||||||
|         public PlaceOfWorkProfile() |  | ||||||
|         { |  | ||||||
|             CreateMap<PlaceOfWorkModel, PlaceOfWork>(MemberList.Destination) |             CreateMap<PlaceOfWorkModel, PlaceOfWork>(MemberList.Destination) | ||||||
|                 .ForMember(p => p.Id, |                 .ForMember(p => p.Id, | ||||||
|                     opts => opts.UseDestinationValue()); |                     opts => opts.UseDestinationValue()); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -2,15 +2,14 @@ | |||||||
| using AutoMapper; | using AutoMapper; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| namespace Infrastructure.Automapper.Profiles | namespace Infrastructure.Automapper.Profiles; | ||||||
|  |  | ||||||
|  | public class UserProfile : Profile | ||||||
| { | { | ||||||
|     public class UserProfile : Profile |     public UserProfile() | ||||||
|     { |     { | ||||||
|         public UserProfile() |  | ||||||
|         { |  | ||||||
|             CreateMap<AuthData, User>(MemberList.Destination) |             CreateMap<AuthData, User>(MemberList.Destination) | ||||||
|                 .ForMember(u => u.Role, |                 .ForMember(u => u.Role, | ||||||
|                     opts => opts.Ignore()); |                     opts => opts.Ignore()); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -3,12 +3,12 @@ using ApplicationLayer.Services.VisaApplications.Requests; | |||||||
| using AutoMapper; | using AutoMapper; | ||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
| namespace Infrastructure.Automapper.Profiles | namespace Infrastructure.Automapper.Profiles; | ||||||
|  |  | ||||||
|  | public class VisaApplicationProfile : Profile | ||||||
| { | { | ||||||
|     public class VisaApplicationProfile : Profile |     public VisaApplicationProfile() | ||||||
|     { |     { | ||||||
|         public VisaApplicationProfile() |  | ||||||
|         { |  | ||||||
|             CreateMap<VisaApplication, VisaApplicationModelForApplicant>(MemberList.Destination); |             CreateMap<VisaApplication, VisaApplicationModelForApplicant>(MemberList.Destination); | ||||||
|  |  | ||||||
|             CreateMap<VisaApplication, VisaApplicationModelForAuthority>(MemberList.Destination) |             CreateMap<VisaApplication, VisaApplicationModelForAuthority>(MemberList.Destination) | ||||||
| @@ -21,5 +21,4 @@ namespace Infrastructure.Automapper.Profiles | |||||||
|                 .ForMember(va => va.ApplicantId, |                 .ForMember(va => va.ApplicantId, | ||||||
|                 opts => opts.Ignore()); |                 opts => opts.Ignore()); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,10 +1,9 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | using ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
|  |  | ||||||
| namespace Infrastructure.Common | namespace Infrastructure.Common; | ||||||
|  |  | ||||||
|  | /// Implements <see cref="IDateTimeProvider"/> | ||||||
|  | public class DateTimeProvider : IDateTimeProvider | ||||||
| { | { | ||||||
|     /// Implements <see cref="IDateTimeProvider"/> |     DateTime IDateTimeProvider.Now() => DateTime.Now; | ||||||
|     public class DateTimeProvider : IDateTimeProvider |  | ||||||
|     { |  | ||||||
|         DateTime IDateTimeProvider.Now() => DateTime.Now; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -2,12 +2,12 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | using ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
| using Microsoft.AspNetCore.Http; | using Microsoft.AspNetCore.Http; | ||||||
|  |  | ||||||
| namespace Infrastructure.Common | namespace Infrastructure.Common; | ||||||
|  |  | ||||||
|  | public class UserIdProvider(IHttpContextAccessor contextAccessor) : IUserIdProvider | ||||||
| { | { | ||||||
|     public class UserIdProvider(IHttpContextAccessor contextAccessor) : IUserIdProvider |     Guid IUserIdProvider.GetUserId() | ||||||
|     { |     { | ||||||
|         Guid IUserIdProvider.GetUserId() |  | ||||||
|         { |  | ||||||
|             var claim = contextAccessor.HttpContext!.User.Claims.SingleOrDefault(claim => claim.Type == ClaimTypes.NameIdentifier); |             var claim = contextAccessor.HttpContext!.User.Claims.SingleOrDefault(claim => claim.Type == ClaimTypes.NameIdentifier); | ||||||
|             if (claim is null) |             if (claim is null) | ||||||
|             { |             { | ||||||
| @@ -15,5 +15,4 @@ namespace Infrastructure.Common | |||||||
|             } |             } | ||||||
|             return Guid.Parse(claim.Value); |             return Guid.Parse(claim.Value); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| using ApplicationLayer.Services.GeneralExceptions; | using ApplicationLayer.Services.GeneralExceptions; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Applicants.Repositories.Exceptions | namespace Infrastructure.Database.Applicants.Repositories.Exceptions; | ||||||
| { |  | ||||||
|     public class ApplicantNotFoundByUserIdException() : EntityNotFoundException("Applicant not found."); | public class ApplicantNotFoundByUserIdException() : EntityNotFoundException("Applicant not found."); | ||||||
| } |  | ||||||
|   | |||||||
| @@ -3,12 +3,12 @@ using Domains.Users; | |||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Users.Configuration | namespace Infrastructure.Database.Users.Configuration; | ||||||
|  |  | ||||||
|  | public class UserConfiguration : IEntityTypeConfiguration<User> | ||||||
| { | { | ||||||
|     public class UserConfiguration : IEntityTypeConfiguration<User> |     public void Configure(EntityTypeBuilder<User> entity) | ||||||
|     { |     { | ||||||
|         public void Configure(EntityTypeBuilder<User> entity) |  | ||||||
|         { |  | ||||||
|             entity.Property(u => u.Email) |             entity.Property(u => u.Email) | ||||||
|                 .IsUnicode(false) |                 .IsUnicode(false) | ||||||
|                 .HasMaxLength(ConfigurationConstraints.EmailLength); |                 .HasMaxLength(ConfigurationConstraints.EmailLength); | ||||||
| @@ -19,5 +19,4 @@ namespace Infrastructure.Database.Users.Configuration | |||||||
|                 .IsUnicode(false) |                 .IsUnicode(false) | ||||||
|                 .HasMaxLength(ConfigurationConstraints.PasswordLength); |                 .HasMaxLength(ConfigurationConstraints.PasswordLength); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -3,20 +3,19 @@ using Domains.Users; | |||||||
| using Infrastructure.Database.Generic; | using Infrastructure.Database.Generic; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Users.Repositories | namespace Infrastructure.Database.Users.Repositories; | ||||||
|  |  | ||||||
|  | /// <inheritdoc cref="IUsersRepository"/> | ||||||
|  | public class UsersRepository(IGenericReader reader, IGenericWriter writer) | ||||||
|  |     : GenericRepository<User>(reader, writer), IUsersRepository | ||||||
| { | { | ||||||
|     /// <inheritdoc cref="IUsersRepository"/> |     async Task<User?> IUsersRepository.FindByEmailAsync(string email, CancellationToken cancellationToken) | ||||||
|     public class UsersRepository(IGenericReader reader, IGenericWriter writer) |  | ||||||
|         : GenericRepository<User>(reader, writer), IUsersRepository |  | ||||||
|     { |     { | ||||||
|         async Task<User?> IUsersRepository.FindByEmailAsync(string email, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             return await LoadDomain().SingleOrDefaultAsync(u => u.Email == email, cancellationToken); |             return await LoadDomain().SingleOrDefaultAsync(u => u.Email == email, cancellationToken); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         async Task<List<User>> IUsersRepository.GetAllOfRoleAsync(Role role, CancellationToken cancellationToken) |     async Task<List<User>> IUsersRepository.GetAllOfRoleAsync(Role role, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             return await LoadDomain().Where(u => u.Role == role).ToListAsync(cancellationToken); |             return await LoadDomain().Where(u => u.Role == role).ToListAsync(cancellationToken); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -2,15 +2,14 @@ | |||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.VisaApplications.Configuration | namespace Infrastructure.Database.VisaApplications.Configuration; | ||||||
|  |  | ||||||
|  | public static class PastVisitConfiguration<T> where T : class, IEntity | ||||||
| { | { | ||||||
|     public static class PastVisitConfiguration<T> where T : class, IEntity |     public static void Configure(OwnedNavigationBuilder<T, PastVisit> entity) | ||||||
|     { |     { | ||||||
|         public static void Configure(OwnedNavigationBuilder<T, PastVisit> entity) |  | ||||||
|         { |  | ||||||
|             entity.Property(pv => pv.DestinationCountry) |             entity.Property(pv => pv.DestinationCountry) | ||||||
|                 .IsUnicode(false) |                 .IsUnicode(false) | ||||||
|                 .HasMaxLength(ConfigurationConstraints.CountryNameLength); |                 .HasMaxLength(ConfigurationConstraints.CountryNameLength); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,7 +1,6 @@ | |||||||
| using ApplicationLayer.Services.GeneralExceptions; | using ApplicationLayer.Services.GeneralExceptions; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.VisaApplications.Repositories.Exceptions | namespace Infrastructure.Database.VisaApplications.Repositories.Exceptions; | ||||||
| { |  | ||||||
|     public class ApplicationNotFoundByApplicantAndApplicationIdException(Guid applicationId) | public class ApplicationNotFoundByApplicantAndApplicationIdException(Guid applicationId) | ||||||
|         : EntityNotFoundException($"Application with id {applicationId} not found for authenticated user"); |     : EntityNotFoundException($"Application with id {applicationId} not found for authenticated user"); | ||||||
| } |  | ||||||
| @@ -2,13 +2,13 @@ | |||||||
| using Microsoft.OpenApi.Models; | using Microsoft.OpenApi.Models; | ||||||
| using Swashbuckle.AspNetCore.SwaggerGen; | using Swashbuckle.AspNetCore.SwaggerGen; | ||||||
|  |  | ||||||
| namespace SchengenVisaApi.Common | namespace SchengenVisaApi.Common; | ||||||
|  |  | ||||||
|  | /// Adds auth for swagger | ||||||
|  | public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions> | ||||||
| { | { | ||||||
|     /// Adds auth for swagger |     void IConfigureOptions<SwaggerGenOptions>.Configure(SwaggerGenOptions options) | ||||||
|     public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions> |  | ||||||
|     { |     { | ||||||
|         void IConfigureOptions<SwaggerGenOptions>.Configure(SwaggerGenOptions options) |  | ||||||
|         { |  | ||||||
|             options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |             options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme | ||||||
|             { |             { | ||||||
|                 In = ParameterLocation.Header, |                 In = ParameterLocation.Header, | ||||||
| @@ -34,5 +34,4 @@ namespace SchengenVisaApi.Common | |||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -1,12 +1,9 @@ | |||||||
| namespace SchengenVisaApi.Common | namespace SchengenVisaApi.Common; | ||||||
| { |  | ||||||
| #pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||||
|     public static class PolicyConstants | public static class PolicyConstants | ||||||
|     { | { | ||||||
|         public const string AdminPolicy = "AdminPolicy"; |     public const string AdminPolicy = "AdminPolicy"; | ||||||
|         public const string ApplicantPolicy = "ApplicantPolicy"; |     public const string ApplicantPolicy = "ApplicantPolicy"; | ||||||
|         public const string ApprovingAuthorityPolicy = "ApprovingAuthorityPolicy"; |     public const string ApprovingAuthorityPolicy = "ApprovingAuthorityPolicy"; | ||||||
|     } |  | ||||||
| #pragma warning enable CS1591 |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | #pragma warning enable CS1591 | ||||||
| @@ -10,106 +10,105 @@ using Microsoft.AspNetCore.Authorization; | |||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| using SchengenVisaApi.Common; | using SchengenVisaApi.Common; | ||||||
|  |  | ||||||
| namespace SchengenVisaApi.Controllers | namespace SchengenVisaApi.Controllers; | ||||||
|  |  | ||||||
|  | ///<summary> Controller for user-auth and registration </summary> | ||||||
|  | [ApiController] | ||||||
|  | [Route("users")] | ||||||
|  | public class UsersController( | ||||||
|  |     IRegisterService registerService, | ||||||
|  |     ILoginService loginService, | ||||||
|  |     IUsersService usersService, | ||||||
|  |     IValidator<RegisterApplicantRequest> registerApplicantRequestValidator, | ||||||
|  |     IValidator<AuthData> authDataValidator) : ControllerBase | ||||||
| { | { | ||||||
|     ///<summary> Controller for user-auth and registration </summary> |     /// <summary> Adds applicant with user account to DB </summary> | ||||||
|     [ApiController] |     [HttpPost] | ||||||
|     [Route("users")] |     [ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|     public class UsersController( |     [ProducesResponseType(StatusCodes.Status409Conflict)] | ||||||
|         IRegisterService registerService, |     [ProducesResponseType(StatusCodes.Status400BadRequest)] | ||||||
|         ILoginService loginService, |     [Route("register")] | ||||||
|         IUsersService usersService, |     public async Task<IActionResult> Register(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||||
|         IValidator<RegisterApplicantRequest> registerApplicantRequestValidator, |  | ||||||
|         IValidator<AuthData> authDataValidator) : ControllerBase |  | ||||||
|     { |     { | ||||||
|         /// <summary> Adds applicant with user account to DB </summary> |         await registerApplicantRequestValidator.ValidateAndThrowAsync(request, cancellationToken); | ||||||
|         [HttpPost] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status409Conflict)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status400BadRequest)] |  | ||||||
|         [Route("register")] |  | ||||||
|         public async Task<IActionResult> Register(RegisterApplicantRequest request, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             await registerApplicantRequestValidator.ValidateAndThrowAsync(request, cancellationToken); |  | ||||||
|  |  | ||||||
|             await registerService.RegisterApplicant(request, cancellationToken); |         await registerService.RegisterApplicant(request, cancellationToken); | ||||||
|             return Ok(); |         return Ok(); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> Adds approving authority with user account to DB </summary> |     /// <summary> Adds approving authority with user account to DB </summary> | ||||||
|         ///<remarks> Accessible only for admins </remarks> |     ///<remarks> Accessible only for admins </remarks> | ||||||
|         [HttpPost] |     [HttpPost] | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |     [ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status409Conflict)] |     [ProducesResponseType(StatusCodes.Status409Conflict)] | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |     [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
|         [ProducesResponseType(StatusCodes.Status401Unauthorized)] |     [ProducesResponseType(StatusCodes.Status401Unauthorized)] | ||||||
|         [ProducesResponseType(StatusCodes.Status400BadRequest)] |     [ProducesResponseType(StatusCodes.Status400BadRequest)] | ||||||
|         [Route("authorities")] |     [Route("authorities")] | ||||||
|         [Authorize(policy: PolicyConstants.AdminPolicy)] |     [Authorize(policy: PolicyConstants.AdminPolicy)] | ||||||
|         public async Task<IActionResult> RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken) |     public async Task<IActionResult> RegisterAuthority(RegisterRequest request, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             await authDataValidator.ValidateAndThrowAsync(request.AuthData, cancellationToken); |         await authDataValidator.ValidateAndThrowAsync(request.AuthData, cancellationToken); | ||||||
|  |  | ||||||
|             await registerService.RegisterAuthority(request, cancellationToken); |         await registerService.RegisterAuthority(request, cancellationToken); | ||||||
|             return Ok(); |         return Ok(); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> Returns JWT-token for authentication </summary> |     /// <summary> Returns JWT-token for authentication </summary> | ||||||
|         [HttpGet] |     [HttpGet] | ||||||
|         [ProducesResponseType<string>(StatusCodes.Status200OK)] |     [ProducesResponseType<string>(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |     [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
|         [Route("login")] |     [Route("login")] | ||||||
|         public async Task<IActionResult> Login(string email, string password, CancellationToken cancellationToken) |     public async Task<IActionResult> Login(string email, string password, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             var result = await loginService.LoginAsync(email, password, cancellationToken); |         var result = await loginService.LoginAsync(email, password, cancellationToken); | ||||||
|             return Ok(result); |         return Ok(result); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> Returns list of authority accounts </summary> |     /// <summary> Returns list of authority accounts </summary> | ||||||
|         /// <remarks> Accessible only for admins </remarks> |     /// <remarks> Accessible only for admins </remarks> | ||||||
|         [HttpGet] |     [HttpGet] | ||||||
|         [ProducesResponseType<List<User>>(StatusCodes.Status200OK)] |     [ProducesResponseType<List<User>>(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |     [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
|         [ProducesResponseType(StatusCodes.Status401Unauthorized)] |     [ProducesResponseType(StatusCodes.Status401Unauthorized)] | ||||||
|         [Route("authorities")] |     [Route("authorities")] | ||||||
|         [Authorize(policy: PolicyConstants.AdminPolicy)] |     [Authorize(policy: PolicyConstants.AdminPolicy)] | ||||||
|         public async Task<IActionResult> GetAuthorityAccounts(CancellationToken cancellationToken) |     public async Task<IActionResult> GetAuthorityAccounts(CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             var result = await usersService.GetAuthoritiesAccountsAsync(cancellationToken); |         var result = await usersService.GetAuthoritiesAccountsAsync(cancellationToken); | ||||||
|             return Ok(result); |         return Ok(result); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> Changes authority's account authentication data </summary> |     /// <summary> Changes authority's account authentication data </summary> | ||||||
|         /// <remarks> Accessible only for admins </remarks> |     /// <remarks> Accessible only for admins </remarks> | ||||||
|         [HttpPut] |     [HttpPut] | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |     [ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status404NotFound)] |     [ProducesResponseType(StatusCodes.Status404NotFound)] | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |     [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
|         [ProducesResponseType(StatusCodes.Status401Unauthorized)] |     [ProducesResponseType(StatusCodes.Status401Unauthorized)] | ||||||
|         [ProducesResponseType(StatusCodes.Status400BadRequest)] |     [ProducesResponseType(StatusCodes.Status400BadRequest)] | ||||||
|         [Route("authorities/{authorityAccountId:guid}")] |     [Route("authorities/{authorityAccountId:guid}")] | ||||||
|         [Authorize(policy: PolicyConstants.AdminPolicy)] |     [Authorize(policy: PolicyConstants.AdminPolicy)] | ||||||
|         public async Task<IActionResult> ChangeAuthorityAuthData(Guid authorityAccountId, AuthData authData, CancellationToken cancellationToken) |     public async Task<IActionResult> ChangeAuthorityAuthData(Guid authorityAccountId, AuthData authData, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             await authDataValidator.ValidateAndThrowAsync(authData, cancellationToken); |         await authDataValidator.ValidateAndThrowAsync(authData, cancellationToken); | ||||||
|  |  | ||||||
|             await usersService.ChangeAccountAuthDataAsync(new ChangeUserAuthDataRequest(authorityAccountId, authData), cancellationToken); |         await usersService.ChangeAccountAuthDataAsync(new ChangeUserAuthDataRequest(authorityAccountId, authData), cancellationToken); | ||||||
|             return Ok(); |         return Ok(); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> Removes authority's account authentication data </summary> |     /// <summary> Removes authority's account authentication data </summary> | ||||||
|         /// <remarks> Accessible only for admins </remarks> |     /// <remarks> Accessible only for admins </remarks> | ||||||
|         [HttpDelete] |     [HttpDelete] | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |     [ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status404NotFound)] |     [ProducesResponseType(StatusCodes.Status404NotFound)] | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |     [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
|         [ProducesResponseType(StatusCodes.Status401Unauthorized)] |     [ProducesResponseType(StatusCodes.Status401Unauthorized)] | ||||||
|         [Route("authorities/{authorityAccountId:guid}")] |     [Route("authorities/{authorityAccountId:guid}")] | ||||||
|         [Authorize(policy: PolicyConstants.AdminPolicy)] |     [Authorize(policy: PolicyConstants.AdminPolicy)] | ||||||
|         public async Task<IActionResult> RemoveAuthorityAccount(Guid authorityAccountId, CancellationToken cancellationToken) |     public async Task<IActionResult> RemoveAuthorityAccount(Guid authorityAccountId, CancellationToken cancellationToken) | ||||||
|         { |     { | ||||||
|             await usersService.RemoveUserAccount(authorityAccountId, cancellationToken); |         await usersService.RemoveUserAccount(authorityAccountId, cancellationToken); | ||||||
|             return Ok(); |         return Ok(); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,4 +1,3 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; |  | ||||||
| using ApplicationLayer.Services.VisaApplications.Handlers; | using ApplicationLayer.Services.VisaApplications.Handlers; | ||||||
| using ApplicationLayer.Services.VisaApplications.Models; | using ApplicationLayer.Services.VisaApplications.Models; | ||||||
| using ApplicationLayer.Services.VisaApplications.Requests; | using ApplicationLayer.Services.VisaApplications.Requests; | ||||||
| @@ -14,7 +13,6 @@ namespace SchengenVisaApi.Controllers; | |||||||
| [Route("visaApplications")] | [Route("visaApplications")] | ||||||
| public class VisaApplicationController( | public class VisaApplicationController( | ||||||
|     IVisaApplicationRequestsHandler visaApplicationRequestsHandler, |     IVisaApplicationRequestsHandler visaApplicationRequestsHandler, | ||||||
|     IUserIdProvider userIdProvider, |  | ||||||
|     IValidator<VisaApplicationCreateRequest> visaApplicationCreateRequestValidator) : ControllerBase |     IValidator<VisaApplicationCreateRequest> visaApplicationCreateRequestValidator) : ControllerBase | ||||||
| { | { | ||||||
|     /// <summary> Returns all applications from DB </summary> |     /// <summary> Returns all applications from DB </summary> | ||||||
| @@ -41,8 +39,7 @@ public class VisaApplicationController( | |||||||
|     [Route("OfApplicant")] |     [Route("OfApplicant")] | ||||||
|     public async Task<IActionResult> GetForApplicant(CancellationToken cancellationToken) |     public async Task<IActionResult> GetForApplicant(CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         var userId = userIdProvider.GetUserId(); |         var result = await visaApplicationRequestsHandler.GetForApplicantAsync(cancellationToken); | ||||||
|         var result = await visaApplicationRequestsHandler.GetForApplicantAsync(userId, cancellationToken); |  | ||||||
|         return Ok(result); |         return Ok(result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -59,8 +56,7 @@ public class VisaApplicationController( | |||||||
|     { |     { | ||||||
|         await visaApplicationCreateRequestValidator.ValidateAndThrowAsync(request, cancellationToken); |         await visaApplicationCreateRequestValidator.ValidateAndThrowAsync(request, cancellationToken); | ||||||
|  |  | ||||||
|         var userId = userIdProvider.GetUserId(); |         await visaApplicationRequestsHandler.HandleCreateRequestAsync(request, cancellationToken); | ||||||
|         await visaApplicationRequestsHandler.HandleCreateRequestAsync(userId, request, cancellationToken); |  | ||||||
|         return Ok(); |         return Ok(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -75,8 +71,7 @@ public class VisaApplicationController( | |||||||
|     [Route("{applicationId:guid}")] |     [Route("{applicationId:guid}")] | ||||||
|     public async Task<IActionResult> CloseApplication(Guid applicationId, CancellationToken cancellationToken) |     public async Task<IActionResult> CloseApplication(Guid applicationId, CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         var userId = userIdProvider.GetUserId(); |         await visaApplicationRequestsHandler.HandleCloseRequestAsync(applicationId, cancellationToken); | ||||||
|         await visaApplicationRequestsHandler.HandleCloseRequestAsync(userId, applicationId, cancellationToken); |  | ||||||
|         return Ok(); |         return Ok(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,67 +6,66 @@ using FluentValidation; | |||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| using Microsoft.AspNetCore.Mvc.Filters; | using Microsoft.AspNetCore.Mvc.Filters; | ||||||
|  |  | ||||||
| namespace SchengenVisaApi.ExceptionFilters | namespace SchengenVisaApi.ExceptionFilters; | ||||||
|  |  | ||||||
|  | /// Handles <see cref="ApiException"/> | ||||||
|  | public class GlobalExceptionsFilter : IAsyncExceptionFilter | ||||||
| { | { | ||||||
|     /// Handles <see cref="ApiException"/> |     /// <inheritdoc cref="IExceptionFilter.OnException"/> | ||||||
|     public class GlobalExceptionsFilter : IAsyncExceptionFilter |     public async Task OnExceptionAsync(ExceptionContext context) | ||||||
|     { |     { | ||||||
|         /// <inheritdoc cref="IExceptionFilter.OnException"/> |         var exception = context.Exception; | ||||||
|         public async Task OnExceptionAsync(ExceptionContext context) |         var problemDetails = new ProblemDetails(); | ||||||
|  |  | ||||||
|  |         switch (exception) | ||||||
|         { |         { | ||||||
|             var exception = context.Exception; |             case ValidationException validationException: | ||||||
|             var problemDetails = new ProblemDetails(); |                 problemDetails.Extensions.Add("Errors", validationException.Errors.Select(e => e.ErrorMessage)); | ||||||
|  |                 problemDetails.Detail = "Validation errors occured"; | ||||||
|  |                 problemDetails.Status = StatusCodes.Status400BadRequest; | ||||||
|  |                 problemDetails.Title = "Bad request"; | ||||||
|  |                 problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; | ||||||
|  |                 break; | ||||||
|  |             case ApiException: | ||||||
|  |                 problemDetails.Detail = exception.Message; | ||||||
|  |                 switch (exception) | ||||||
|  |                 { | ||||||
|  |                     case EntityNotFoundException: | ||||||
|  |                         problemDetails.Status = StatusCodes.Status404NotFound; | ||||||
|  |                         problemDetails.Title = "Requested entity not found"; | ||||||
|  |                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"; | ||||||
|  |                         break; | ||||||
|  |                     case IncorrectLoginDataException: | ||||||
|  |                         problemDetails.Status = StatusCodes.Status403Forbidden; | ||||||
|  |                         problemDetails.Title = "Auth failed"; | ||||||
|  |                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.3"; | ||||||
|  |                         break; | ||||||
|  |                     case AlreadyExistsException: | ||||||
|  |                         problemDetails.Status = StatusCodes.Status409Conflict; | ||||||
|  |                         problemDetails.Title = "Already exists"; | ||||||
|  |                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; | ||||||
|  |                         break; | ||||||
|  |                     case ApplicationAlreadyProcessedException: | ||||||
|  |                         problemDetails.Status = StatusCodes.Status409Conflict; | ||||||
|  |                         problemDetails.Title = "Already processed"; | ||||||
|  |                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; | ||||||
|  |                         break; | ||||||
|  |                     default: | ||||||
|  |                         problemDetails.Status = StatusCodes.Status400BadRequest; | ||||||
|  |                         problemDetails.Title = "Bad request"; | ||||||
|  |                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; | ||||||
|  |                         break; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|             switch (exception) |                 break; | ||||||
|             { |             default: | ||||||
|                 case ValidationException validationException: |                 problemDetails.Status = StatusCodes.Status500InternalServerError; | ||||||
|                     problemDetails.Extensions.Add("Errors", validationException.Errors.Select(e => e.ErrorMessage)); |                 problemDetails.Title = "An unhandled error occured"; | ||||||
|                     problemDetails.Detail = "Validation errors occured"; |                 problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.6.1"; | ||||||
|                     problemDetails.Status = StatusCodes.Status400BadRequest; |                 break; | ||||||
|                     problemDetails.Title = "Bad request"; |  | ||||||
|                     problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; |  | ||||||
|                     break; |  | ||||||
|                 case ApiException: |  | ||||||
|                     problemDetails.Detail = exception.Message; |  | ||||||
|                     switch (exception) |  | ||||||
|                     { |  | ||||||
|                         case EntityNotFoundException: |  | ||||||
|                             problemDetails.Status = StatusCodes.Status404NotFound; |  | ||||||
|                             problemDetails.Title = "Requested entity not found"; |  | ||||||
|                             problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"; |  | ||||||
|                             break; |  | ||||||
|                         case IncorrectLoginDataException: |  | ||||||
|                             problemDetails.Status = StatusCodes.Status403Forbidden; |  | ||||||
|                             problemDetails.Title = "Auth failed"; |  | ||||||
|                             problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.3"; |  | ||||||
|                             break; |  | ||||||
|                         case AlreadyExistsException: |  | ||||||
|                             problemDetails.Status = StatusCodes.Status409Conflict; |  | ||||||
|                             problemDetails.Title = "Already exists"; |  | ||||||
|                             problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; |  | ||||||
|                             break; |  | ||||||
|                         case ApplicationAlreadyProcessedException: |  | ||||||
|                             problemDetails.Status = StatusCodes.Status409Conflict; |  | ||||||
|                             problemDetails.Title = "Already processed"; |  | ||||||
|                             problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; |  | ||||||
|                             break; |  | ||||||
|                         default: |  | ||||||
|                             problemDetails.Status = StatusCodes.Status400BadRequest; |  | ||||||
|                             problemDetails.Title = "Bad request"; |  | ||||||
|                             problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; |  | ||||||
|                             break; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     break; |  | ||||||
|                 default: |  | ||||||
|                     problemDetails.Status = StatusCodes.Status500InternalServerError; |  | ||||||
|                     problemDetails.Title = "An unhandled error occured"; |  | ||||||
|                     problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.6.1"; |  | ||||||
|                     break; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             await Results.Problem(problemDetails).ExecuteAsync(context.HttpContext); |  | ||||||
|             context.ExceptionHandled = true; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         await Results.Problem(problemDetails).ExecuteAsync(context.HttpContext); | ||||||
|  |         context.ExceptionHandled = true; | ||||||
|     } |     } | ||||||
| } | } | ||||||
		Reference in New Issue
	
	Block a user
	 prtsie
					prtsie