Admin controller, Locations controller, requests to add available countries, request to get available countries
This commit is contained in:
		| @@ -1,4 +0,0 @@ | |||||||
| namespace ApplicationLayer.AuthServices.LoginService.Exceptions |  | ||||||
| { |  | ||||||
|     public class IncorrectLoginDataException() : Exception("Incorrect email or password"); |  | ||||||
| } |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| using ApplicationLayer.AuthServices.Requests; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.AuthServices.RegisterService.Exceptions |  | ||||||
| { |  | ||||||
|     public class UserAlreadyExistsException(RegisterApplicantRequest request) : Exception($"User with email '{request.Email}' already exists"); |  | ||||||
| } |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| using ApplicationLayer.AuthServices.NeededServices; |  | ||||||
| using ApplicationLayer.AuthServices.RegisterService.Exceptions; |  | ||||||
| using ApplicationLayer.AuthServices.Requests; |  | ||||||
| using Domains.Users; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.AuthServices.RegisterService |  | ||||||
| { |  | ||||||
|     /// <inheritdoc cref="IRegisterService"/> |  | ||||||
|     public class RegisterService(IUsersRepository users) : IRegisterService |  | ||||||
|     { |  | ||||||
|         async Task IRegisterService.Register(RegisterApplicantRequest request, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             if (await users.FindByEmailAsync(request.Email, cancellationToken) is not null) |  | ||||||
|             { |  | ||||||
|                 throw new UserAlreadyExistsException(request); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             //TODO mapper |  | ||||||
|             var user = new User |  | ||||||
|             { |  | ||||||
|                 Email = request.Email, |  | ||||||
|                 Password = request.Password, |  | ||||||
|                 Role = Role.Applicant |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             await users.AddAsync(user, cancellationToken); |  | ||||||
|             await users.SaveAsync(cancellationToken); |  | ||||||
|             users.GetAllAsync(cancellationToken); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| namespace ApplicationLayer.AuthServices.Requests |  | ||||||
| { |  | ||||||
|     public record RegisterApplicantRequest(string Email, string Password); |  | ||||||
| } |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| namespace ApplicationLayer.AuthServices.Requests |  | ||||||
| { |  | ||||||
|     public record UserLoginRequest(string Email, string Password); |  | ||||||
| } |  | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models; | namespace ApplicationLayer.DataAccessingServices.Applicants.Models; | ||||||
| 
 | 
 | ||||||
| public class AddressModel | public class AddressModel | ||||||
| { | { | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Models; | namespace ApplicationLayer.DataAccessingServices.Applicants.Models; | ||||||
| 
 | 
 | ||||||
| public class PlaceOfWorkModel | public class PlaceOfWorkModel | ||||||
| { | { | ||||||
| @@ -4,4 +4,8 @@ using Domains.ApplicantDomain; | |||||||
| namespace ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | namespace ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||||
|  |  | ||||||
| /// Repository pattern for <see cref="Applicant"/> | /// Repository pattern for <see cref="Applicant"/> | ||||||
| public interface IApplicantsRepository : IGenericRepository<Applicant>; | public interface IApplicantsRepository : IGenericRepository<Applicant> | ||||||
|  | { | ||||||
|  |     /// Find <see cref="Applicant"/> by Identifier | ||||||
|  |     Task<Applicant> FindByUserIdAsync(Guid userId, CancellationToken cancellationToken); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.AuthServices.LoginService.Exceptions; | ||||||
|  | using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; | ||||||
|  | using ApplicationLayer.DataAccessingServices.AuthServices.Requests; | ||||||
|  | using Domains.Users; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService | ||||||
|  | { | ||||||
|  |     public class DevelopmentLoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService | ||||||
|  |     { | ||||||
|  |         async Task<string> ILoginService.LoginAsync(UserLoginRequest request, CancellationToken cancellationToken) | ||||||
|  |         { | ||||||
|  |             if (request is { Email: "admin@mail.ru", Password: "admin" }) | ||||||
|  |             { | ||||||
|  |                 var admin = new User { Role = Role.Admin }; | ||||||
|  |  | ||||||
|  |                 return tokenGenerator.CreateToken(admin); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var user = await users.FindByEmailAsync(request.Email, cancellationToken); | ||||||
|  |             if (user is null || user.Password != request.Password) | ||||||
|  |             { | ||||||
|  |                 throw new IncorrectLoginDataException(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return tokenGenerator.CreateToken(user); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | using ApplicationLayer.GeneralExceptions; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService.Exceptions | ||||||
|  | { | ||||||
|  |     public class IncorrectLoginDataException() : ApiException("Incorrect email or password"); | ||||||
|  | } | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| using ApplicationLayer.AuthServices.Requests; | using ApplicationLayer.DataAccessingServices.AuthServices.Requests; | ||||||
| 
 | 
 | ||||||
| namespace ApplicationLayer.AuthServices.LoginService | namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService | ||||||
| { | { | ||||||
|     /// Handles <see cref="UserLoginRequest"/> |     /// Handles <see cref="UserLoginRequest"/> | ||||||
|     public interface ILoginService |     public interface ILoginService | ||||||
| @@ -1,8 +1,8 @@ | |||||||
| using ApplicationLayer.AuthServices.LoginService.Exceptions; | using ApplicationLayer.DataAccessingServices.AuthServices.LoginService.Exceptions; | ||||||
| using ApplicationLayer.AuthServices.NeededServices; | using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; | ||||||
| using ApplicationLayer.AuthServices.Requests; | using ApplicationLayer.DataAccessingServices.AuthServices.Requests; | ||||||
| 
 | 
 | ||||||
| namespace ApplicationLayer.AuthServices.LoginService | namespace ApplicationLayer.DataAccessingServices.AuthServices.LoginService | ||||||
| { | { | ||||||
|     /// <inheritdoc cref="ILoginService"/> |     /// <inheritdoc cref="ILoginService"/> | ||||||
|     public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService |     public class LoginService(IUsersRepository users, ITokenGenerator tokenGenerator) : ILoginService | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| using Domains.Users; | using Domains.Users; | ||||||
| 
 | 
 | ||||||
| namespace ApplicationLayer.AuthServices.NeededServices | namespace ApplicationLayer.DataAccessingServices.AuthServices.NeededServices | ||||||
| { | { | ||||||
|     public interface ITokenGenerator |     public interface ITokenGenerator | ||||||
|     { |     { | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| using ApplicationLayer.GeneralNeededServices; | using ApplicationLayer.GeneralNeededServices; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
| 
 | 
 | ||||||
| namespace ApplicationLayer.AuthServices.NeededServices | namespace ApplicationLayer.DataAccessingServices.AuthServices.NeededServices | ||||||
| { | { | ||||||
|     /// Repository pattern for <see cref="User"/> |     /// Repository pattern for <see cref="User"/> | ||||||
|     public interface IUsersRepository : IGenericRepository<User> |     public interface IUsersRepository : IGenericRepository<User> | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.AuthServices.Requests; | ||||||
|  | using ApplicationLayer.GeneralExceptions; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.AuthServices.RegisterService.Exceptions | ||||||
|  | { | ||||||
|  |     public class UserAlreadyExistsException(RegisterApplicantRequest request) : AlreadyExistsException($"User with email '{request.Email}' already exists"); | ||||||
|  | } | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| using ApplicationLayer.AuthServices.Requests; | using ApplicationLayer.DataAccessingServices.AuthServices.Requests; | ||||||
| 
 | 
 | ||||||
| namespace ApplicationLayer.AuthServices.RegisterService | namespace ApplicationLayer.DataAccessingServices.AuthServices.RegisterService | ||||||
| { | { | ||||||
|     /// Handles <see cref="RegisterApplicantRequest"/> |     /// Handles <see cref="RegisterApplicantRequest"/> | ||||||
|     public interface IRegisterService |     public interface IRegisterService | ||||||
| @@ -0,0 +1,71 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||||
|  | using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; | ||||||
|  | using ApplicationLayer.DataAccessingServices.AuthServices.RegisterService.Exceptions; | ||||||
|  | using ApplicationLayer.DataAccessingServices.AuthServices.Requests; | ||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||||
|  | using ApplicationLayer.GeneralNeededServices; | ||||||
|  | using Domains.ApplicantDomain; | ||||||
|  | using Domains.Users; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.AuthServices.RegisterService | ||||||
|  | { | ||||||
|  |     /// <inheritdoc cref="IRegisterService"/> | ||||||
|  |     public class RegisterService( | ||||||
|  |         IUsersRepository users, | ||||||
|  |         IApplicantsRepository applicants, | ||||||
|  |         ICitiesRepository cities, | ||||||
|  |         IUnitOfWork unitOfWork) : IRegisterService | ||||||
|  |     { | ||||||
|  |         async Task IRegisterService.Register(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||||
|  |         { | ||||||
|  |             if (await users.FindByEmailAsync(request.Email, cancellationToken) is not null) | ||||||
|  |             { | ||||||
|  |                 throw new UserAlreadyExistsException(request); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             //TODO mapper | ||||||
|  |             var user = new User { Email = request.Email, Password = request.Password, Role = Role.Applicant }; | ||||||
|  |  | ||||||
|  |             var applicantCity = await cities.GetByIdAsync(request.CityOfBirthId, cancellationToken); | ||||||
|  |             var placeOfWorkCity = await cities.GetByIdAsync(request.PlaceOfWork.Address.CityId, cancellationToken); | ||||||
|  |             var placeOfWorkAddress = new Address | ||||||
|  |             { | ||||||
|  |                 Country = placeOfWorkCity.Country, | ||||||
|  |                 City = placeOfWorkCity, | ||||||
|  |                 Building = request.PlaceOfWork.Address.Building, | ||||||
|  |                 Street = request.PlaceOfWork.Address.Street | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             var placeOfWork = new PlaceOfWork | ||||||
|  |             { | ||||||
|  |                 Name = request.PlaceOfWork.Name, | ||||||
|  |                 Address = placeOfWorkAddress, | ||||||
|  |                 PhoneNum = request.PlaceOfWork.PhoneNum | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             var applicant = new Applicant | ||||||
|  |             { | ||||||
|  |                 Citizenship = request.Citizenship, | ||||||
|  |                 CitizenshipByBirth = request.CitizenshipByBirth, | ||||||
|  |                 Gender = request.Gender, | ||||||
|  |                 Name = request.ApplicantName, | ||||||
|  |                 Passport = request.Passport, | ||||||
|  |                 BirthDate = request.BirthDate, | ||||||
|  |                 FatherName = request.FatherName, | ||||||
|  |                 JobTitle = request.JobTitle, | ||||||
|  |                 MaritalStatus = request.MaritalStatus, | ||||||
|  |                 MotherName = request.MotherName, | ||||||
|  |                 UserId = user.Id, | ||||||
|  |                 CityOfBirth = applicantCity, | ||||||
|  |                 CountryOfBirth = applicantCity.Country, | ||||||
|  |                 IsNonResident = request.IsNonResident, | ||||||
|  |                 PlaceOfWork = placeOfWork | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             await users.AddAsync(user, cancellationToken); | ||||||
|  |             await applicants.AddAsync(applicant, cancellationToken); | ||||||
|  |  | ||||||
|  |             await unitOfWork.SaveAsync(cancellationToken); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,22 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.Applicants.Models; | ||||||
|  | using Domains.ApplicantDomain; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.AuthServices.Requests | ||||||
|  | { | ||||||
|  |     public record RegisterApplicantRequest( | ||||||
|  |         string Email, | ||||||
|  |         string Password, | ||||||
|  |         Name ApplicantName, | ||||||
|  |         Passport Passport, | ||||||
|  |         DateTime BirthDate, | ||||||
|  |         Guid CityOfBirthId, | ||||||
|  |         string Citizenship, | ||||||
|  |         string CitizenshipByBirth, | ||||||
|  |         Gender Gender, | ||||||
|  |         MaritalStatus MaritalStatus, | ||||||
|  |         Name FatherName, | ||||||
|  |         Name MotherName, | ||||||
|  |         string JobTitle, | ||||||
|  |         PlaceOfWorkModel PlaceOfWork, | ||||||
|  |         bool IsNonResident); | ||||||
|  | } | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | namespace ApplicationLayer.DataAccessingServices.AuthServices.Requests | ||||||
|  | { | ||||||
|  |     public record UserLoginRequest(string Email, string Password); | ||||||
|  | } | ||||||
| @@ -3,4 +3,11 @@ using Domains.LocationDomain; | |||||||
|  |  | ||||||
| namespace ApplicationLayer.DataAccessingServices.Locations.NeededServices; | namespace ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||||
|  |  | ||||||
| public interface ICountriesRepository : IGenericRepository<Country>; | public interface ICountriesRepository : IGenericRepository<Country> | ||||||
|  | { | ||||||
|  |     /// Gets country by name | ||||||
|  |     /// <param name="countryName">Name of country to seek</param> | ||||||
|  |     /// <param name="cancellationToken">Cancellation Token</param> | ||||||
|  |     /// <returns>Country or null if not found</returns> | ||||||
|  |     Task<Country?> FindByName(string countryName, CancellationToken cancellationToken); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -0,0 +1,36 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions; | ||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.Requests; | ||||||
|  | using ApplicationLayer.GeneralNeededServices; | ||||||
|  | using Domains.LocationDomain; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests | ||||||
|  | { | ||||||
|  |     /// <inheritdoc cref="IEditLocationsRequestsHandler"/> | ||||||
|  |     public class EditLocationsRequestsHandler(ICountriesRepository countries, IUnitOfWork unitOfWork) : IEditLocationsRequestsHandler | ||||||
|  |     { | ||||||
|  |         async Task IEditLocationsRequestsHandler.AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken) | ||||||
|  |         { | ||||||
|  |             if (await countries.FindByName(request.CountryName, cancellationToken) is not null) | ||||||
|  |             { | ||||||
|  |                 throw new CountryAlreadyExists(request.CountryName); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (request.Cities.Distinct().Count() < request.Cities.Length) | ||||||
|  |             { | ||||||
|  |                 throw new MultipleIdenticalCitiesInCountry(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var country = new Country | ||||||
|  |             { | ||||||
|  |                 Name = request.CountryName, | ||||||
|  |                 IsSchengen = request.IsSchengen, | ||||||
|  |                 Cities = request.Cities.Select(cityName => new City { Name = cityName }).ToList() | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             await countries.AddAsync(country, cancellationToken); | ||||||
|  |  | ||||||
|  |             await unitOfWork.SaveAsync(cancellationToken); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | using ApplicationLayer.GeneralExceptions; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions | ||||||
|  | { | ||||||
|  |     public class CountryAlreadyExists(string countryName) : AlreadyExistsException($"{countryName} already exists."); | ||||||
|  | } | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | using ApplicationLayer.GeneralExceptions; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions | ||||||
|  | { | ||||||
|  |     public class MultipleIdenticalCitiesInCountry() : ApiException("There are multiple cities with one name in the country."); | ||||||
|  | } | ||||||
| @@ -0,0 +1,11 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.Requests; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests | ||||||
|  | { | ||||||
|  |     /// Handles edit requests of locations from admins | ||||||
|  |     public interface IEditLocationsRequestsHandler | ||||||
|  |     { | ||||||
|  |         /// Handles add country requests | ||||||
|  |         Task AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,12 @@ | |||||||
|  | using Domains.LocationDomain; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests | ||||||
|  | { | ||||||
|  |     /// Handles location requests | ||||||
|  |     public interface ILocationRequestsHandler | ||||||
|  |     { | ||||||
|  |         /// Handle get request | ||||||
|  |         /// <returns>List of available countries</returns> | ||||||
|  |         Task<List<Country>> HandleGetRequestAsync(CancellationToken cancellationToken); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||||
|  | using Domains.LocationDomain; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests | ||||||
|  | { | ||||||
|  |     /// <inheritdoc cref="ILocationRequestsHandler"/> | ||||||
|  |     public class LocationRequestsHandler(ICountriesRepository countries) : ILocationRequestsHandler | ||||||
|  |     { | ||||||
|  |         async Task<List<Country>> ILocationRequestsHandler.HandleGetRequestAsync(CancellationToken cancellationToken) | ||||||
|  |         { | ||||||
|  |             return await countries.GetAllAsync(cancellationToken); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | namespace ApplicationLayer.DataAccessingServices.Locations.Requests | ||||||
|  | { | ||||||
|  |     public record AddCountryRequest(string CountryName, bool IsSchengen, string[] Cities); | ||||||
|  | } | ||||||
| @@ -3,9 +3,9 @@ using Domains.VisaApplicationDomain; | |||||||
| 
 | 
 | ||||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||||
| 
 | 
 | ||||||
| public interface IVisaApplicationsRequestHandler | public interface IVisaApplicationRequestsHandler | ||||||
| { | { | ||||||
|     Task<List<VisaApplication>> Get(CancellationToken cancellationToken); |     Task<List<VisaApplication>> Get(CancellationToken cancellationToken); | ||||||
| 
 | 
 | ||||||
|     void HandleCreateRequest(VisaApplicationCreateRequest request, CancellationToken cancellationToken); |     void HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken); | ||||||
| } | } | ||||||
| @@ -1,8 +1,9 @@ | |||||||
| using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Models; | using ApplicationLayer.DataAccessingServices.VisaApplications.Models; | ||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | ||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | ||||||
| using Domains.ApplicantDomain; | using ApplicationLayer.GeneralNeededServices; | ||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||||
| @@ -10,42 +11,18 @@ namespace ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | |||||||
| /// Handles visa requests | /// Handles visa requests | ||||||
| public class VisaApplicationRequestsHandler( | public class VisaApplicationRequestsHandler( | ||||||
|     IVisaApplicationsRepository applications, |     IVisaApplicationsRepository applications, | ||||||
|     ICitiesRepository cities, |     IApplicantsRepository applicants, | ||||||
|     ICountriesRepository countries) : IVisaApplicationsRequestHandler |     ICountriesRepository countries, | ||||||
|  |     IUnitOfWork unitOfWork) : IVisaApplicationRequestsHandler | ||||||
| { | { | ||||||
|     public async Task<List<VisaApplication>> Get(CancellationToken cancellationToken) => await applications.GetAllAsync(cancellationToken); |     public async Task<List<VisaApplication>> Get(CancellationToken cancellationToken) => await applications.GetAllAsync(cancellationToken); | ||||||
|  |  | ||||||
|     public async void HandleCreateRequest(VisaApplicationCreateRequest request, CancellationToken cancellationToken) |     public async void HandleCreateRequest(Guid userId, VisaApplicationCreateRequest request, CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|  |         //TODO fix | ||||||
|         //TODO mapper |         //TODO mapper | ||||||
|         var cityOfBirth = await cities.GetByIdAsync(request.BirthCityId, cancellationToken); |  | ||||||
|         var cityOfWork = await cities.GetByIdAsync(request.PlaceOfWork.Address.CityId, cancellationToken); |  | ||||||
|  |  | ||||||
|         var addressOfWork = new Address |         var applicant = await applicants.FindByUserIdAsync(userId, cancellationToken); | ||||||
|         { |  | ||||||
|             City = cityOfWork, |  | ||||||
|             Country = cityOfWork.Country, |  | ||||||
|             Building = request.PlaceOfWork.Address.Building, |  | ||||||
|             Street = request.PlaceOfWork.Address.Street |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         var applicant = new Applicant |  | ||||||
|         { |  | ||||||
|             MaritalStatus = request.MaritalStatus, |  | ||||||
|             Name = request.FullName, |  | ||||||
|             Passport = request.Passport, |  | ||||||
|             Gender = request.Gender, |  | ||||||
|             Citizenship = request.CitizenShip, |  | ||||||
|             BirthDate = request.BirthDate, |  | ||||||
|             FatherName = request.FatherName, |  | ||||||
|             JobTitle = request.JobTitle, |  | ||||||
|             MotherName = request.MotherName, |  | ||||||
|             CitizenshipByBirth = request.CitizenshipByBirth, |  | ||||||
|             CityOfBirth = cityOfBirth, |  | ||||||
|             CountryOfBirth = cityOfBirth.Country, |  | ||||||
|             IsNonResident = request.IsNonResident, |  | ||||||
|             PlaceOfWork = new PlaceOfWork { Address = addressOfWork, Name = request.PlaceOfWork.Name, PhoneNum = request.PlaceOfWork.PhoneNum } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         var pastVisits = request.PastVisits.Select(m => ConvertPastVisitModelToPastVisit(m, cancellationToken).Result).ToList(); |         var pastVisits = request.PastVisits.Select(m => ConvertPastVisitModelToPastVisit(m, cancellationToken).Result).ToList(); | ||||||
|         var visaApplication = new VisaApplication |         var visaApplication = new VisaApplication | ||||||
| @@ -64,7 +41,8 @@ public class VisaApplicationRequestsHandler( | |||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         await applications.AddAsync(visaApplication, cancellationToken); |         await applications.AddAsync(visaApplication, cancellationToken); | ||||||
|         await applications.SaveAsync(cancellationToken); |  | ||||||
|  |         await unitOfWork.SaveAsync(cancellationToken); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private async Task<PastVisit> ConvertPastVisitModelToPastVisit(PastVisitModel model, CancellationToken cancellationToken) |     private async Task<PastVisit> ConvertPastVisitModelToPastVisit(PastVisitModel model, CancellationToken cancellationToken) | ||||||
|   | |||||||
| @@ -1,25 +1,11 @@ | |||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Models; | using ApplicationLayer.DataAccessingServices.VisaApplications.Models; | ||||||
| using Domains.ApplicantDomain; |  | ||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
| namespace ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | namespace ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | ||||||
|  |  | ||||||
| /// Model of visa request from user | /// Model of visa request from user | ||||||
| public record VisaApplicationCreateRequest( | public record VisaApplicationCreateRequest( | ||||||
|     Name FullName, |  | ||||||
|     Passport Passport, |  | ||||||
|     DateTime BirthDate, |  | ||||||
|     Guid BirthCityId, |  | ||||||
|     string CitizenShip, |  | ||||||
|     string CitizenshipByBirth, |  | ||||||
|     Gender Gender, |  | ||||||
|     MaritalStatus MaritalStatus, |  | ||||||
|     Name FatherName, |  | ||||||
|     Name MotherName, |  | ||||||
|     bool IsNonResident, |  | ||||||
|     ReentryPermit ReentryPermit, |     ReentryPermit ReentryPermit, | ||||||
|     string JobTitle, |  | ||||||
|     PlaceOfWorkModel PlaceOfWork, |  | ||||||
|     Guid DestinationCountryId, |     Guid DestinationCountryId, | ||||||
|     VisaCategory VisaCategory, |     VisaCategory VisaCategory, | ||||||
|     bool IsForGroup, |     bool IsForGroup, | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| using ApplicationLayer.AuthServices.LoginService; | using ApplicationLayer.DataAccessingServices.AuthServices.LoginService; | ||||||
| using ApplicationLayer.AuthServices.RegisterService; | using ApplicationLayer.DataAccessingServices.AuthServices.RegisterService; | ||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests; | ||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests; | ||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
|  |  | ||||||
| @@ -9,12 +11,22 @@ namespace ApplicationLayer; | |||||||
| public static class DependencyInjection | public static class DependencyInjection | ||||||
| { | { | ||||||
|     /// Add services for Application layer |     /// Add services for Application layer | ||||||
|     public static IServiceCollection AddApplicationLayer(this IServiceCollection services) |     public static IServiceCollection AddApplicationLayer(this IServiceCollection services, bool isDevelopment = false) | ||||||
|     { |     { | ||||||
|         services.AddScoped<IVisaApplicationsRequestHandler, VisaApplicationRequestsHandler>(); |         services.AddScoped<IVisaApplicationRequestsHandler, VisaApplicationRequestsHandler>(); | ||||||
|  |         services.AddScoped<ILocationRequestsHandler, LocationRequestsHandler>(); | ||||||
|  |         services.AddScoped<IEditLocationsRequestsHandler, EditLocationsRequestsHandler>(); | ||||||
|  |  | ||||||
|         services.AddScoped<IRegisterService, RegisterService>(); |         services.AddScoped<IRegisterService, RegisterService>(); | ||||||
|         services.AddScoped<ILoginService, LoginService>(); |  | ||||||
|  |         if (isDevelopment) | ||||||
|  |         { | ||||||
|  |             services.AddScoped<ILoginService, DevelopmentLoginService>(); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             services.AddScoped<ILoginService, LoginService>(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return services; |         return services; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | namespace ApplicationLayer.GeneralExceptions | ||||||
|  | { | ||||||
|  |     public class AlreadyExistsException(string message) : ApiException(message); | ||||||
|  | } | ||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | namespace ApplicationLayer.GeneralExceptions | ||||||
|  | { | ||||||
|  |     public class ApiException(string message) : Exception(message); | ||||||
|  | } | ||||||
| @@ -34,7 +34,4 @@ public interface IGenericRepository<T> where T : class, IEntity | |||||||
|     /// </summary> |     /// </summary> | ||||||
|     /// <param name="entity">Entity to remove</param> |     /// <param name="entity">Entity to remove</param> | ||||||
|     void Remove(T entity); |     void Remove(T entity); | ||||||
|  |  | ||||||
|     /// Save changes in storage |  | ||||||
|     Task SaveAsync(CancellationToken cancellationToken); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| namespace Infrastructure.Database; | namespace ApplicationLayer.GeneralNeededServices; | ||||||
| 
 | 
 | ||||||
| public interface IUnitOfWork | public interface IUnitOfWork | ||||||
| { | { | ||||||
| @@ -6,7 +6,9 @@ namespace Domains.ApplicantDomain; | |||||||
| public class Applicant : IEntity | public class Applicant : IEntity | ||||||
| { | { | ||||||
|     /// Unique identifier of the <see cref="Applicant"/> |     /// Unique identifier of the <see cref="Applicant"/> | ||||||
|     public Guid Id { get; set; } |     public Guid Id { get; private set; } = Guid.NewGuid(); | ||||||
|  |  | ||||||
|  |     public Guid UserId { get; set; } | ||||||
|  |  | ||||||
|     /// Full name of the <see cref="Applicant"/> |     /// Full name of the <see cref="Applicant"/> | ||||||
|     public Name Name { get; set; } = null!; |     public Name Name { get; set; } = null!; | ||||||
|   | |||||||
| @@ -1,4 +1,6 @@ | |||||||
| namespace Domains.LocationDomain; | using System.Text.Json.Serialization; | ||||||
|  |  | ||||||
|  | namespace Domains.LocationDomain; | ||||||
|  |  | ||||||
| /// Model of a city | /// Model of a city | ||||||
| public class City : IEntity | public class City : IEntity | ||||||
| @@ -10,5 +12,6 @@ public class City : IEntity | |||||||
|     public string Name { get; set; } = null!; |     public string Name { get; set; } = null!; | ||||||
|  |  | ||||||
|     /// <see cref="LocationDomain.Country"/> in which the city is located |     /// <see cref="LocationDomain.Country"/> in which the city is located | ||||||
|  |     [JsonIgnore] | ||||||
|     public Country Country { get; set; } = null!; |     public Country Country { get; set; } = null!; | ||||||
| } | } | ||||||
| @@ -1,5 +1,5 @@ | |||||||
| using System.IdentityModel.Tokens.Jwt; | using System.IdentityModel.Tokens.Jwt; | ||||||
| using ApplicationLayer.AuthServices.NeededServices; | using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; | ||||||
| using ApplicationLayer.GeneralNeededServices; | using ApplicationLayer.GeneralNeededServices; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| using System.IdentityModel.Tokens.Jwt; | using System.IdentityModel.Tokens.Jwt; | ||||||
| using System.Security.Claims; | using System.Security.Claims; | ||||||
| using ApplicationLayer.AuthServices.NeededServices; | using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; | ||||||
| using ApplicationLayer.GeneralNeededServices; | using ApplicationLayer.GeneralNeededServices; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| @@ -14,7 +14,7 @@ namespace Infrastructure.Auth | |||||||
|             var claims = new List<Claim> |             var claims = new List<Claim> | ||||||
|             { |             { | ||||||
|                 new(ClaimTypes.Role, user.Role.ToString()), |                 new(ClaimTypes.Role, user.Role.ToString()), | ||||||
|                 new(ClaimTypes.Email, user.Email) |                 new(ClaimTypes.NameIdentifier, user.Id.ToString()) | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             var token = new JwtSecurityToken( |             var token = new JwtSecurityToken( | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
|  | using Domains.Users; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||||||
|  |  | ||||||
| @@ -16,6 +17,7 @@ public class ApplicantConfiguration : IEntityTypeConfiguration<Applicant> | |||||||
|  |  | ||||||
|         entity.HasOne(a => a.CityOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); |         entity.HasOne(a => a.CityOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); | ||||||
|         entity.HasOne(a => a.CountryOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); |         entity.HasOne(a => a.CountryOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); | ||||||
|  |         entity.HasOne<User>().WithOne().HasForeignKey<Applicant>(a => a.UserId); | ||||||
|  |  | ||||||
|         entity.Property(p => p.Citizenship) |         entity.Property(p => p.Citizenship) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
|  | using Infrastructure.Database.Applicants.Repositories.Exceptions; | ||||||
| using Infrastructure.Database.Generic; | using Infrastructure.Database.Generic; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
|  |  | ||||||
| @@ -8,9 +9,8 @@ namespace Infrastructure.Database.Applicants.Repositories; | |||||||
| /// Repository pattern for <see cref="Applicant"/> | /// Repository pattern for <see cref="Applicant"/> | ||||||
| /// <param name="reader"><inheritdoc cref="IGenericReader"/></param> | /// <param name="reader"><inheritdoc cref="IGenericReader"/></param> | ||||||
| /// <param name="writer"><inheritdoc cref="IGenericWriter"/></param> | /// <param name="writer"><inheritdoc cref="IGenericWriter"/></param> | ||||||
| /// <param name="unitOfWork"><inheritdoc cref="IUnitOfWork"/></param> | public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter writer) | ||||||
| public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) |     : GenericRepository<Applicant>(reader, writer), IApplicantsRepository | ||||||
|     : GenericRepository<Applicant>(reader, writer, unitOfWork), IApplicantsRepository |  | ||||||
| { | { | ||||||
|     protected override IQueryable<Applicant> LoadDomain() |     protected override IQueryable<Applicant> LoadDomain() | ||||||
|     { |     { | ||||||
| @@ -19,4 +19,10 @@ public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter w | |||||||
|             .Include(a => a.CityOfBirth) |             .Include(a => a.CityOfBirth) | ||||||
|             .Include(a => a.PlaceOfWork); |             .Include(a => a.PlaceOfWork); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async Task<Applicant> IApplicantsRepository.FindByUserIdAsync(Guid userId, CancellationToken cancellationToken) | ||||||
|  |     { | ||||||
|  |         var result = await LoadDomain().SingleOrDefaultAsync(a => a.UserId == userId, cancellationToken); | ||||||
|  |         return result ?? throw new ApplicantNotFoundByUserIdException(userId); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,10 @@ | |||||||
|  | using Domains.ApplicantDomain; | ||||||
|  | using Infrastructure.Database.GeneralExceptions; | ||||||
|  |  | ||||||
|  | namespace Infrastructure.Database.Applicants.Repositories.Exceptions | ||||||
|  | { | ||||||
|  |     public class ApplicantNotFoundByUserIdException(Guid id) : EntityNotFoundException<Applicant>("Applicant not found.") | ||||||
|  |     { | ||||||
|  |         public Guid UserId { get; private set; } = id; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| using System.Reflection; | using System.Reflection; | ||||||
|  | using ApplicationLayer.GeneralNeededServices; | ||||||
| using Infrastructure.Database.Generic; | using Infrastructure.Database.Generic; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,8 +1,9 @@ | |||||||
| using Domains; | using ApplicationLayer.GeneralExceptions; | ||||||
|  | using Domains; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.GeneralExceptions; | namespace Infrastructure.Database.GeneralExceptions; | ||||||
|  |  | ||||||
| /// Exception to throw when entity not found | /// Exception to throw when entity not found | ||||||
| /// <typeparam name="T">Not found entity type</typeparam> | /// <typeparam name="T">Not found entity type</typeparam> | ||||||
| public class EntityNotFoundException<T>(string message) : Exception(message) | public class EntityNotFoundException<T>(string message) : ApiException(message) | ||||||
|     where T : class, IEntity; |     where T : class, IEntity; | ||||||
|   | |||||||
| @@ -7,10 +7,9 @@ namespace Infrastructure.Database.Generic; | |||||||
|  |  | ||||||
| /// Generic repository pattern | /// Generic repository pattern | ||||||
| /// <param name="writer"><inheritdoc cref="IGenericWriter"/></param> | /// <param name="writer"><inheritdoc cref="IGenericWriter"/></param> | ||||||
| /// <param name="unitOfWork"><inheritdoc cref="IUnitOfWork"/></param> |  | ||||||
| /// <typeparam name="T">Type of entity</typeparam> | /// <typeparam name="T">Type of entity</typeparam> | ||||||
| /// <remarks>Should be inherited to create typed repositories</remarks> | /// <remarks>Should be inherited to create typed repositories</remarks> | ||||||
| public abstract class GenericRepository<T>(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) : IGenericRepository<T> | public abstract class GenericRepository<T>(IGenericReader reader, IGenericWriter writer) : IGenericRepository<T> | ||||||
|     where T : class, IEntity |     where T : class, IEntity | ||||||
| { | { | ||||||
|     /// <inheritdoc cref="IGenericRepository{T}.GetAllAsync"/> |     /// <inheritdoc cref="IGenericRepository{T}.GetAllAsync"/> | ||||||
| @@ -41,10 +40,6 @@ public abstract class GenericRepository<T>(IGenericReader reader, IGenericWriter | |||||||
|         writer.Remove(entity); |         writer.Remove(entity); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// <inheritdoc cref="IGenericRepository{T}.SaveAsync"/> |  | ||||||
|     public async Task SaveAsync(CancellationToken cancellationToken) |  | ||||||
|         => await unitOfWork.SaveAsync(cancellationToken); |  | ||||||
|  |  | ||||||
|     /// Should be overriden to load navigation properties of entity |     /// Should be overriden to load navigation properties of entity | ||||||
|     protected virtual IQueryable<T> LoadDomain() |     protected virtual IQueryable<T> LoadDomain() | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| using Domains; | using ApplicationLayer.GeneralNeededServices; | ||||||
|  | using Domains; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Generic; | namespace Infrastructure.Database.Generic; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,8 +8,10 @@ public class CountryConfiguration : IEntityTypeConfiguration<Country> | |||||||
| { | { | ||||||
|     public void Configure(EntityTypeBuilder<Country> entity) |     public void Configure(EntityTypeBuilder<Country> entity) | ||||||
|     { |     { | ||||||
|         entity.Property(p => p.Name) |         entity.Property(c => c.Name) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(70); |             .HasMaxLength(70); | ||||||
|  |  | ||||||
|  |         entity.HasIndex(c => c.Name).IsUnique(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -5,8 +5,8 @@ using Microsoft.EntityFrameworkCore; | |||||||
|  |  | ||||||
| namespace Infrastructure.Database.Locations.Repositories.Cities; | namespace Infrastructure.Database.Locations.Repositories.Cities; | ||||||
|  |  | ||||||
| public sealed class CitiesRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) | public sealed class CitiesRepository(IGenericReader reader, IGenericWriter writer) | ||||||
|     : GenericRepository<City>(reader, writer, unitOfWork), ICitiesRepository |     : GenericRepository<City>(reader, writer), ICitiesRepository | ||||||
| { | { | ||||||
|     protected override IQueryable<City> LoadDomain() |     protected override IQueryable<City> LoadDomain() | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -5,11 +5,17 @@ using Microsoft.EntityFrameworkCore; | |||||||
|  |  | ||||||
| namespace Infrastructure.Database.Locations.Repositories.Countries; | namespace Infrastructure.Database.Locations.Repositories.Countries; | ||||||
|  |  | ||||||
| public sealed class CountriesRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) | public sealed class CountriesRepository(IGenericReader reader, IGenericWriter writer) | ||||||
|     : GenericRepository<Country>(reader, writer, unitOfWork), ICountriesRepository |     : GenericRepository<Country>(reader, writer), ICountriesRepository | ||||||
| { | { | ||||||
|     protected override IQueryable<Country> LoadDomain() |     protected override IQueryable<Country> LoadDomain() | ||||||
|     { |     { | ||||||
|         return base.LoadDomain().Include(c => c.Cities); |         return base.LoadDomain().Include(c => c.Cities); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async Task<Country?> ICountriesRepository.FindByName(string countryName, CancellationToken cancellationToken) | ||||||
|  |     { | ||||||
|  |         var result = await LoadDomain().SingleOrDefaultAsync(c => c.Name == countryName, cancellationToken); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
| } | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| using ApplicationLayer.AuthServices.NeededServices; | using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
| using Infrastructure.Database.Generic; | using Infrastructure.Database.Generic; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| @@ -6,8 +6,8 @@ using Microsoft.EntityFrameworkCore; | |||||||
| namespace Infrastructure.Database.Users.Repositories | namespace Infrastructure.Database.Users.Repositories | ||||||
| { | { | ||||||
|     /// <inheritdoc cref="IUsersRepository"/> |     /// <inheritdoc cref="IUsersRepository"/> | ||||||
|     public class UsersRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) |     public class UsersRepository(IGenericReader reader, IGenericWriter writer) | ||||||
|         : GenericRepository<User>(reader, writer, unitOfWork), IUsersRepository |         : GenericRepository<User>(reader, writer), IUsersRepository | ||||||
|     { |     { | ||||||
|         async Task<User?> IUsersRepository.FindByEmailAsync(string email, CancellationToken cancellationToken) |         async Task<User?> IUsersRepository.FindByEmailAsync(string email, CancellationToken cancellationToken) | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ using Microsoft.EntityFrameworkCore; | |||||||
|  |  | ||||||
| namespace Infrastructure.Database.VisaApplications.Repositories; | namespace Infrastructure.Database.VisaApplications.Repositories; | ||||||
|  |  | ||||||
| public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWriter writer, IUnitOfWork unitOfWork) | public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWriter writer) | ||||||
|     : GenericRepository<VisaApplication>(reader, writer, unitOfWork), IVisaApplicationsRepository |     : GenericRepository<VisaApplication>(reader, writer), IVisaApplicationsRepository | ||||||
| { | { | ||||||
|     protected override IQueryable<VisaApplication> LoadDomain() |     protected override IQueryable<VisaApplication> LoadDomain() | ||||||
|     { |     { | ||||||
|   | |||||||
| @@ -1,11 +1,9 @@ | |||||||
| using ApplicationLayer.AuthServices.NeededServices; | using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | ||||||
| using ApplicationLayer.DataAccessingServices.Applicants.NeededServices; | using ApplicationLayer.DataAccessingServices.AuthServices.NeededServices; | ||||||
| using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | using ApplicationLayer.DataAccessingServices.Locations.NeededServices; | ||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | using ApplicationLayer.DataAccessingServices.VisaApplications.NeededServices; | ||||||
| using ApplicationLayer.GeneralNeededServices; | using ApplicationLayer.GeneralNeededServices; | ||||||
| using Infrastructure.Auth; |  | ||||||
| using Infrastructure.Common; | using Infrastructure.Common; | ||||||
| using Infrastructure.Database; |  | ||||||
| using Infrastructure.Database.Applicants.Repositories; | using Infrastructure.Database.Applicants.Repositories; | ||||||
| using Infrastructure.Database.Generic; | using Infrastructure.Database.Generic; | ||||||
| using Infrastructure.Database.Locations.Repositories.Cities; | using Infrastructure.Database.Locations.Repositories.Cities; | ||||||
|   | |||||||
| @@ -0,0 +1,37 @@ | |||||||
|  | using Microsoft.Extensions.Options; | ||||||
|  | using Microsoft.OpenApi.Models; | ||||||
|  | using Swashbuckle.AspNetCore.SwaggerGen; | ||||||
|  |  | ||||||
|  | namespace SchengenVisaApi.Common | ||||||
|  | { | ||||||
|  |     public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions> | ||||||
|  |     { | ||||||
|  |         void IConfigureOptions<SwaggerGenOptions>.Configure(SwaggerGenOptions options) | ||||||
|  |         { | ||||||
|  |             options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme | ||||||
|  |             { | ||||||
|  |                 In = ParameterLocation.Header, | ||||||
|  |                 Description = "Provide a JWT-token.", | ||||||
|  |                 Name = "Authorization", | ||||||
|  |                 Type = SecuritySchemeType.Http, | ||||||
|  |                 BearerFormat = "JWT", | ||||||
|  |                 Scheme = "Bearer" | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             options.AddSecurityRequirement(new OpenApiSecurityRequirement | ||||||
|  |             { | ||||||
|  |                 { | ||||||
|  |                     new OpenApiSecurityScheme | ||||||
|  |                     { | ||||||
|  |                         Reference = new OpenApiReference | ||||||
|  |                         { | ||||||
|  |                             Type = ReferenceType.SecurityScheme, | ||||||
|  |                             Id = "Bearer" | ||||||
|  |                         } | ||||||
|  |                     }, | ||||||
|  |                     Array.Empty<string>() | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								SchengenVisaApi/SchengenVisaApi/Common/PolicyConstants.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								SchengenVisaApi/SchengenVisaApi/Common/PolicyConstants.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | namespace SchengenVisaApi.Common | ||||||
|  | { | ||||||
|  | #pragma warning disable CS1591 | ||||||
|  |     public static class PolicyConstants | ||||||
|  |     { | ||||||
|  |         public const string AdminPolicy = "AdminPolicy"; | ||||||
|  |         public const string ApplicantPolicy = "ApplicantPolicy"; | ||||||
|  |         public const string ApprovingAuthorityPolicy = "ApprovingAuthorityPolicy"; | ||||||
|  |     } | ||||||
|  | #pragma warning enable CS1591 | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,22 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests; | ||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.Requests; | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  | using SchengenVisaApi.Common; | ||||||
|  |  | ||||||
|  | namespace SchengenVisaApi.Controllers | ||||||
|  | { | ||||||
|  |     [ApiController] | ||||||
|  |     [Route("admin")] | ||||||
|  |     [Authorize(policy: PolicyConstants.AdminPolicy)] | ||||||
|  |     public class AdminController(IEditLocationsRequestsHandler requestsHandler) : ControllerBase | ||||||
|  |     { | ||||||
|  |         [HttpPost] | ||||||
|  |         [Route("country")] | ||||||
|  |         public async Task<IActionResult> AddCountry(AddCountryRequest request, CancellationToken cancellationToken) | ||||||
|  |         { | ||||||
|  |             await requestsHandler.AddCountryAsync(request, cancellationToken); | ||||||
|  |             return Ok(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,16 @@ | |||||||
|  | using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.ApplicantRequests; | ||||||
|  | using Microsoft.AspNetCore.Mvc; | ||||||
|  |  | ||||||
|  | namespace SchengenVisaApi.Controllers | ||||||
|  | { | ||||||
|  |     [ApiController] | ||||||
|  |     [Route("countries")] | ||||||
|  |     public class LocationsController(ILocationRequestsHandler requestsHandler) : ControllerBase | ||||||
|  |     { | ||||||
|  |         [HttpGet] | ||||||
|  |         public async Task<IActionResult> GetAvailableLocations(CancellationToken cancellationToken) | ||||||
|  |         { | ||||||
|  |             return Ok(await requestsHandler.HandleGetRequestAsync(cancellationToken)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,14 +1,13 @@ | |||||||
| using ApplicationLayer.AuthServices.LoginService; | using ApplicationLayer.DataAccessingServices.AuthServices.LoginService; | ||||||
| using ApplicationLayer.AuthServices.RegisterService; | using ApplicationLayer.DataAccessingServices.AuthServices.RegisterService; | ||||||
| using ApplicationLayer.AuthServices.Requests; | using ApplicationLayer.DataAccessingServices.AuthServices.Requests; | ||||||
| using Microsoft.AspNetCore.Identity.Data; |  | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
|  |  | ||||||
| namespace SchengenVisaApi.Controllers | namespace SchengenVisaApi.Controllers | ||||||
| { | { | ||||||
|     [ApiController] |     [ApiController] | ||||||
|     [Route("auth")] |     [Route("auth")] | ||||||
|     public class UsersController(IRegisterService registerService, ILoginService loginService) : Controller |     public class UsersController(IRegisterService registerService, ILoginService loginService) : ControllerBase | ||||||
|     { |     { | ||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         public async Task<IActionResult> Register(RegisterApplicantRequest request, CancellationToken cancellationToken) |         public async Task<IActionResult> Register(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||||
|   | |||||||
| @@ -1,23 +1,29 @@ | |||||||
|  | using System.Security.Claims; | ||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | using ApplicationLayer.DataAccessingServices.VisaApplications.Handlers; | ||||||
| using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | using ApplicationLayer.DataAccessingServices.VisaApplications.Requests; | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
|  | using SchengenVisaApi.Common; | ||||||
|  |  | ||||||
| namespace SchengenVisaApi.Controllers; | namespace SchengenVisaApi.Controllers; | ||||||
|  |  | ||||||
| [ApiController] | [ApiController] | ||||||
| [Route("[controller]")] | [Route("[controller]")] | ||||||
| public class VisaApplicationController(IVisaApplicationsRequestHandler visaApplicationsRequestHandler) : ControllerBase | [Authorize(policy: PolicyConstants.ApplicantPolicy)] | ||||||
|  | public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : ControllerBase | ||||||
| { | { | ||||||
|  |     //TODO remove | ||||||
|     [HttpGet] |     [HttpGet] | ||||||
|     public async Task<IActionResult> Get(CancellationToken cancellationToken) |     public async Task<IActionResult> Get(CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         var result = await visaApplicationsRequestHandler.Get(cancellationToken); |         var result = await visaApplicationRequestsHandler.Get(cancellationToken); | ||||||
|         return Ok(result); |         return Ok(result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     [HttpPost] |     [HttpPost] | ||||||
|     public void Create(VisaApplicationCreateRequest request, CancellationToken cancellationToken) |     public void Create(VisaApplicationCreateRequest request, CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         visaApplicationsRequestHandler.HandleCreateRequest(request, cancellationToken); |         var userId = Guid.Parse(HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value); | ||||||
|  |         visaApplicationRequestsHandler.HandleCreateRequest(userId, request, cancellationToken); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,16 @@ | |||||||
| using System.Reflection; | using System.Reflection; | ||||||
|  | using System.Security.Claims; | ||||||
| using System.Text; | using System.Text; | ||||||
| using ApplicationLayer; | using ApplicationLayer; | ||||||
|  | using Domains.Users; | ||||||
| using Infrastructure; | using Infrastructure; | ||||||
| using Infrastructure.Auth; | using Infrastructure.Auth; | ||||||
| using Microsoft.AspNetCore.Authentication.JwtBearer; | using Microsoft.AspNetCore.Authentication.JwtBearer; | ||||||
|  | using Microsoft.AspNetCore.Authorization; | ||||||
|  | using Microsoft.Extensions.Options; | ||||||
| using Microsoft.IdentityModel.Tokens; | using Microsoft.IdentityModel.Tokens; | ||||||
|  | using SchengenVisaApi.Common; | ||||||
|  | using Swashbuckle.AspNetCore.SwaggerGen; | ||||||
|  |  | ||||||
| namespace SchengenVisaApi; | namespace SchengenVisaApi; | ||||||
|  |  | ||||||
| @@ -19,7 +25,7 @@ public static class DependencyInjection | |||||||
|  |  | ||||||
|         builder.Services |         builder.Services | ||||||
|             .AddInfrastructure(config, environment.IsDevelopment()) |             .AddInfrastructure(config, environment.IsDevelopment()) | ||||||
|             .AddApplicationLayer() |             .AddApplicationLayer(environment.IsDevelopment()) | ||||||
|             .AddAuth(config) |             .AddAuth(config) | ||||||
|             .AddPresentation(environment); |             .AddPresentation(environment); | ||||||
|     } |     } | ||||||
| @@ -52,7 +58,7 @@ public static class DependencyInjection | |||||||
|  |  | ||||||
|         services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |         services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) | ||||||
|             .AddJwtBearer(opts => opts.TokenValidationParameters = parameters); |             .AddJwtBearer(opts => opts.TokenValidationParameters = parameters); | ||||||
|         services.AddAuthorization(); |         services.AddAuthorizationBuilder().ConfigureAuthorizationPolicies(); | ||||||
|  |  | ||||||
|         services.AddTokenGenerator(new TokenGeneratorOptions( |         services.AddTokenGenerator(new TokenGeneratorOptions( | ||||||
|             Issuer: parameters.ValidIssuer!, |             Issuer: parameters.ValidIssuer!, | ||||||
| @@ -64,9 +70,24 @@ public static class DependencyInjection | |||||||
|         return services; |         return services; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Configure roles | ||||||
|  |     private static void ConfigureAuthorizationPolicies(this AuthorizationBuilder builder) | ||||||
|  |     { | ||||||
|  |         builder.AddPolicy( | ||||||
|  |                 PolicyConstants.AdminPolicy, | ||||||
|  |                 p => p.RequireClaim(ClaimTypes.Role, Role.Admin.ToString())) | ||||||
|  |             .AddPolicy( | ||||||
|  |                 PolicyConstants.ApprovingAuthorityPolicy, | ||||||
|  |                 p => p.RequireClaim(ClaimTypes.Role, Role.ApprovingAuthority.ToString())) | ||||||
|  |             .AddPolicy( | ||||||
|  |                 PolicyConstants.ApplicantPolicy, | ||||||
|  |                 p => p.RequireClaim(ClaimTypes.Role, Role.Applicant.ToString())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Add swagger |     /// Add swagger | ||||||
|     private static void AddSwagger(this IServiceCollection services) |     private static void AddSwagger(this IServiceCollection services) | ||||||
|     { |     { | ||||||
|  |         services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>(); | ||||||
|         services.AddSwaggerGen(options => |         services.AddSwaggerGen(options => | ||||||
|         { |         { | ||||||
|             var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; |             var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user