Removed location entities, fixed configurations and controllers' comments
This commit is contained in:
		| @@ -1,6 +1,5 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.LoginService; | using ApplicationLayer.Services.AuthServices.LoginService; | ||||||
| using ApplicationLayer.Services.AuthServices.RegisterService; | using ApplicationLayer.Services.AuthServices.RegisterService; | ||||||
| using ApplicationLayer.Services.Locations.RequestHandlers; |  | ||||||
| using ApplicationLayer.Services.VisaApplications.Handlers; | using ApplicationLayer.Services.VisaApplications.Handlers; | ||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
|  |  | ||||||
| @@ -13,7 +12,6 @@ public static class DependencyInjection | |||||||
|     public static IServiceCollection AddApplicationLayer(this IServiceCollection services, bool isDevelopment = false) |     public static IServiceCollection AddApplicationLayer(this IServiceCollection services, bool isDevelopment = false) | ||||||
|     { |     { | ||||||
|         services.AddScoped<IVisaApplicationRequestsHandler, VisaApplicationRequestsHandler>(); |         services.AddScoped<IVisaApplicationRequestsHandler, VisaApplicationRequestsHandler>(); | ||||||
|         services.AddScoped<ILocationRequestsHandler, LocationRequestsHandler>(); |  | ||||||
|  |  | ||||||
|         services.AddScoped<IRegisterService, RegisterService>(); |         services.AddScoped<IRegisterService, RegisterService>(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ using ApplicationLayer.Services.Applicants.NeededServices; | |||||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | using ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
| using ApplicationLayer.Services.AuthServices.RegisterService.Exceptions; | using ApplicationLayer.Services.AuthServices.RegisterService.Exceptions; | ||||||
| using ApplicationLayer.Services.AuthServices.Requests; | using ApplicationLayer.Services.AuthServices.Requests; | ||||||
| using ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using Domains.Users; | using Domains.Users; | ||||||
|  |  | ||||||
| @@ -13,7 +12,6 @@ namespace ApplicationLayer.Services.AuthServices.RegisterService | |||||||
|     public class RegisterService( |     public class RegisterService( | ||||||
|         IUsersRepository users, |         IUsersRepository users, | ||||||
|         IApplicantsRepository applicants, |         IApplicantsRepository applicants, | ||||||
|         ICitiesRepository cities, |  | ||||||
|         IUnitOfWork unitOfWork) : IRegisterService |         IUnitOfWork unitOfWork) : IRegisterService | ||||||
|     { |     { | ||||||
|         async Task IRegisterService.Register(RegisterApplicantRequest request, CancellationToken cancellationToken) |         async Task IRegisterService.Register(RegisterApplicantRequest request, CancellationToken cancellationToken) | ||||||
| @@ -27,21 +25,6 @@ namespace ApplicationLayer.Services.AuthServices.RegisterService | |||||||
|             //TODO mapper |             //TODO mapper | ||||||
|             var user = new User { Email = request.Email, Password = request.Password, Role = Role.Applicant }; |             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 |             var applicant = new Applicant | ||||||
|             { |             { | ||||||
|                 Citizenship = request.Citizenship, |                 Citizenship = request.Citizenship, | ||||||
| @@ -55,10 +38,10 @@ namespace ApplicationLayer.Services.AuthServices.RegisterService | |||||||
|                 MaritalStatus = request.MaritalStatus, |                 MaritalStatus = request.MaritalStatus, | ||||||
|                 MotherName = request.MotherName, |                 MotherName = request.MotherName, | ||||||
|                 UserId = user.Id, |                 UserId = user.Id, | ||||||
|                 CityOfBirth = applicantCity, |                 CityOfBirth = request.CityOfBirth, | ||||||
|                 CountryOfBirth = applicantCity.Country, |                 CountryOfBirth = request.CountryOfBirth, | ||||||
|                 IsNonResident = request.IsNonResident, |                 IsNonResident = request.IsNonResident, | ||||||
|                 PlaceOfWork = placeOfWork |                 PlaceOfWork = request.PlaceOfWork | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             await users.AddAsync(user, cancellationToken); |             await users.AddAsync(user, cancellationToken); | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| using ApplicationLayer.Services.Applicants.Models; | using Domains.ApplicantDomain; | ||||||
| using Domains.ApplicantDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.AuthServices.Requests | namespace ApplicationLayer.Services.AuthServices.Requests | ||||||
| { | { | ||||||
| @@ -9,7 +8,8 @@ namespace ApplicationLayer.Services.AuthServices.Requests | |||||||
|         Name ApplicantName, |         Name ApplicantName, | ||||||
|         Passport Passport, |         Passport Passport, | ||||||
|         DateTime BirthDate, |         DateTime BirthDate, | ||||||
|         Guid CityOfBirthId, |         string CityOfBirth, | ||||||
|  |         string CountryOfBirth, | ||||||
|         string Citizenship, |         string Citizenship, | ||||||
|         string CitizenshipByBirth, |         string CitizenshipByBirth, | ||||||
|         Gender Gender, |         Gender Gender, | ||||||
| @@ -17,6 +17,6 @@ namespace ApplicationLayer.Services.AuthServices.Requests | |||||||
|         Name FatherName, |         Name FatherName, | ||||||
|         Name MotherName, |         Name MotherName, | ||||||
|         string JobTitle, |         string JobTitle, | ||||||
|         PlaceOfWorkModel PlaceOfWork, |         PlaceOfWork PlaceOfWork, | ||||||
|         bool IsNonResident) : RegisterRequest(Email, Password); |         bool IsNonResident) : RegisterRequest(Email, Password); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +0,0 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
|  |  | ||||||
| public interface ICitiesRepository : IGenericRepository<City> |  | ||||||
| { |  | ||||||
|     /// Get <see cref="City"/> by name and country identifier |  | ||||||
|     Task<City?> GetByNameAsync(Guid requestId, string existingCity, CancellationToken cancellationToken); |  | ||||||
| } |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
|  |  | ||||||
| public interface ICountriesRepository : IGenericRepository<Country> |  | ||||||
| { |  | ||||||
|     /// Gets country by name |  | ||||||
|     Task<Country?> FindByNameAsync(string countryName, CancellationToken cancellationToken); |  | ||||||
|  |  | ||||||
|     /// Gets country by identifier |  | ||||||
|     Task<Country?> FindByIdAsync(Guid id, CancellationToken cancellationToken); |  | ||||||
| } |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| using ApplicationLayer.Services.GeneralExceptions; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.RequestHandlers.Exceptions |  | ||||||
| { |  | ||||||
|     public class CityCanNotBeDeletedException(string cityName) |  | ||||||
|         : EntityUsedInDatabaseException($"{cityName} can not be deleted because some applicants live or work in it"); |  | ||||||
| } |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| using ApplicationLayer.GeneralExceptions; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.RequestHandlers.Exceptions |  | ||||||
| { |  | ||||||
|     public class CountryAlreadyExists(string countryName) : AlreadyExistsException($"{countryName} already exists."); |  | ||||||
| } |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| using ApplicationLayer.Services.GeneralExceptions; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.RequestHandlers.Exceptions |  | ||||||
| { |  | ||||||
|     public class CountryNotFoundException(string countryName) : EntityNotFoundException<Country>($"Country {countryName} is not supported."); |  | ||||||
| } |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| using ApplicationLayer.GeneralExceptions; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.RequestHandlers.Exceptions |  | ||||||
| { |  | ||||||
|     public class MultipleIdenticalCitiesInCountryException() : ApiException("There are multiple cities with one name in the country."); |  | ||||||
| } |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| using ApplicationLayer.Services.Locations.Requests; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.RequestHandlers |  | ||||||
| { |  | ||||||
|     /// Handles location requests |  | ||||||
|     public interface ILocationRequestsHandler |  | ||||||
|     { |  | ||||||
|         /// Handle get request |  | ||||||
|         /// <returns>List of available countries</returns> |  | ||||||
|         Task<List<Country>> HandleGetRequestAsync(CancellationToken cancellationToken); |  | ||||||
|  |  | ||||||
|         /// Handles <see cref="AddCountryRequest"/> |  | ||||||
|         Task AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken); |  | ||||||
|  |  | ||||||
|         /// Handles <see cref="UpdateCountryRequest"/> |  | ||||||
|         Task UpdateCountryAsync(UpdateCountryRequest request, CancellationToken cancellationToken); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; |  | ||||||
| using ApplicationLayer.Services.Applicants.NeededServices; |  | ||||||
| using ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
| using ApplicationLayer.Services.Locations.RequestHandlers.Exceptions; |  | ||||||
| using ApplicationLayer.Services.Locations.Requests; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.RequestHandlers |  | ||||||
| { |  | ||||||
|     /// <inheritdoc cref="ILocationRequestsHandler"/> |  | ||||||
|     public class LocationRequestsHandler( |  | ||||||
|         ICountriesRepository countries, |  | ||||||
|         ICitiesRepository cities, |  | ||||||
|         IApplicantsRepository applicants, |  | ||||||
|         IUnitOfWork unitOfWork) : ILocationRequestsHandler |  | ||||||
|     { |  | ||||||
|         async Task<List<Country>> ILocationRequestsHandler.HandleGetRequestAsync(CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             return await countries.GetAllAsync(cancellationToken); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         async Task ILocationRequestsHandler.AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             if (await countries.FindByNameAsync(request.CountryName, cancellationToken) is not null) |  | ||||||
|             { |  | ||||||
|                 throw new CountryAlreadyExists(request.CountryName); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (request.Cities.Distinct().Count() < request.Cities.Length) |  | ||||||
|             { |  | ||||||
|                 throw new MultipleIdenticalCitiesInCountryException(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             //todo mapper |  | ||||||
|             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); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         async Task ILocationRequestsHandler.UpdateCountryAsync(UpdateCountryRequest request, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             if (await countries.FindByNameAsync(request.CountryName, cancellationToken) is not null) |  | ||||||
|             { |  | ||||||
|                 throw new CountryAlreadyExists(request.CountryName); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var country = await countries.FindByIdAsync(request.Id, cancellationToken); |  | ||||||
|             if (country is null) |  | ||||||
|             { |  | ||||||
|                 throw new CountryNotFoundException(request.CountryName); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var existingCities = country.Cities; |  | ||||||
|             var citiesToAdd = request.Cities.Except(existingCities.Select(c => c.Name)).ToList(); |  | ||||||
|             var citiesToRemove = existingCities.Where(c => !request.Cities.Contains(c.Name)); |  | ||||||
|             var applicantsList = await applicants.GetAllAsync(cancellationToken); |  | ||||||
|  |  | ||||||
|             //todo mapper |  | ||||||
|             foreach (var city in citiesToRemove) |  | ||||||
|             { |  | ||||||
|                 if (applicantsList.All(a => a.CityOfBirth.Id != city.Id && a.PlaceOfWork.Address.City.Id != city.Id)) |  | ||||||
|                 { |  | ||||||
|                     cities.Remove(city); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     throw new CityCanNotBeDeletedException(city.Name); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             foreach (var city in citiesToAdd) |  | ||||||
|             { |  | ||||||
|                 await cities.AddAsync(new City { Name = city, Country = country }, cancellationToken); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             country.Name = request.CountryName; |  | ||||||
|             country.IsSchengen = request.IsSchengen; |  | ||||||
|  |  | ||||||
|             await countries.UpdateAsync(country, cancellationToken); |  | ||||||
|  |  | ||||||
|             await unitOfWork.SaveAsync(cancellationToken); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| namespace ApplicationLayer.Services.Locations.Requests |  | ||||||
| { |  | ||||||
|     public record AddCountryRequest(string CountryName, bool IsSchengen, string[] Cities); |  | ||||||
| } |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| namespace ApplicationLayer.Services.Locations.Requests |  | ||||||
| { |  | ||||||
|     public record UpdateCountryRequest(Guid Id, string CountryName, bool IsSchengen, string[] Cities); |  | ||||||
| } |  | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | using ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
| using ApplicationLayer.Services.Applicants.NeededServices; | using ApplicationLayer.Services.Applicants.NeededServices; | ||||||
| using ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
| using ApplicationLayer.Services.VisaApplications.Models; | using ApplicationLayer.Services.VisaApplications.Models; | ||||||
| using ApplicationLayer.Services.VisaApplications.NeededServices; | using ApplicationLayer.Services.VisaApplications.NeededServices; | ||||||
| using ApplicationLayer.Services.VisaApplications.Requests; | using ApplicationLayer.Services.VisaApplications.Requests; | ||||||
| @@ -12,7 +11,6 @@ namespace ApplicationLayer.Services.VisaApplications.Handlers; | |||||||
| public class VisaApplicationRequestsHandler( | public class VisaApplicationRequestsHandler( | ||||||
|     IVisaApplicationsRepository applications, |     IVisaApplicationsRepository applications, | ||||||
|     IApplicantsRepository applicants, |     IApplicantsRepository applicants, | ||||||
|     ICountriesRepository countries, |  | ||||||
|     IUnitOfWork unitOfWork) : IVisaApplicationRequestsHandler |     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); | ||||||
| @@ -24,7 +22,7 @@ public class VisaApplicationRequestsHandler( | |||||||
|         var visaApplications = await applications.GetOfApplicantAsync(applicantId, cancellationToken); |         var visaApplications = await applications.GetOfApplicantAsync(applicantId, cancellationToken); | ||||||
|         return visaApplications.Select(va => new VisaApplicationModelForApplicant |         return visaApplications.Select(va => new VisaApplicationModelForApplicant | ||||||
|             { |             { | ||||||
|                 DestinationCountry = va.DestinationCountry.Name, |                 DestinationCountry = va.DestinationCountry, | ||||||
|                 ValidDaysRequested = va.ValidDaysRequested, |                 ValidDaysRequested = va.ValidDaysRequested, | ||||||
|                 ReentryPermit = va.ReentryPermit, |                 ReentryPermit = va.ReentryPermit, | ||||||
|                 VisaCategory = va.VisaCategory, |                 VisaCategory = va.VisaCategory, | ||||||
| @@ -33,8 +31,7 @@ public class VisaApplicationRequestsHandler( | |||||||
|                 ForGroup = va.ForGroup, |                 ForGroup = va.ForGroup, | ||||||
|                 PastVisas = va.PastVisas, |                 PastVisas = va.PastVisas, | ||||||
|                 RequestDate = va.RequestDate, |                 RequestDate = va.RequestDate, | ||||||
|                 PastVisits = va.PastVisits.Select(pv => |                 PastVisits = va.PastVisits | ||||||
|                     new PastVisitModel { DestinationCountry = pv.DestinationCountry.Name, StartDate = pv.StartDate, EndDate = pv.EndDate }).ToList() |  | ||||||
|             }).ToList(); |             }).ToList(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -44,18 +41,17 @@ public class VisaApplicationRequestsHandler( | |||||||
|  |  | ||||||
|         var applicant = await applicants.FindByUserIdAsync(userId, cancellationToken); |         var applicant = await applicants.FindByUserIdAsync(userId, cancellationToken); | ||||||
|  |  | ||||||
|         var pastVisits = request.PastVisits.Select(m => ConvertPastVisitModelToPastVisit(m, cancellationToken).Result).ToList(); |  | ||||||
|         var visaApplication = new VisaApplication |         var visaApplication = new VisaApplication | ||||||
|         { |         { | ||||||
|             Applicant = applicant, |             ApplicantId = applicant.Id, | ||||||
|             RequestedNumberOfEntries = request.RequestedNumberOfEntries, |             RequestedNumberOfEntries = request.RequestedNumberOfEntries, | ||||||
|             ValidDaysRequested = request.ValidDaysRequested, |             ValidDaysRequested = request.ValidDaysRequested, | ||||||
|             ReentryPermit = request.ReentryPermit, |             ReentryPermit = request.ReentryPermit, | ||||||
|             VisaCategory = request.VisaCategory, |             VisaCategory = request.VisaCategory, | ||||||
|             PermissionToDestCountry = request.PermissionToDestCountry, |             PermissionToDestCountry = request.PermissionToDestCountry, | ||||||
|             DestinationCountry = await countries.GetByIdAsync(request.DestinationCountryId, cancellationToken), |             DestinationCountry = request.DestinationCountry, | ||||||
|             PastVisas = request.PastVisas.ToList(), |             PastVisas = request.PastVisas.ToList(), | ||||||
|             PastVisits = pastVisits, |             PastVisits = request.PastVisits.ToList(), | ||||||
|             ForGroup = request.IsForGroup, |             ForGroup = request.IsForGroup, | ||||||
|             RequestDate = DateTime.Today |             RequestDate = DateTime.Today | ||||||
|         }; |         }; | ||||||
| @@ -64,14 +60,4 @@ public class VisaApplicationRequestsHandler( | |||||||
|  |  | ||||||
|         await unitOfWork.SaveAsync(cancellationToken); |         await unitOfWork.SaveAsync(cancellationToken); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private async Task<PastVisit> ConvertPastVisitModelToPastVisit(PastVisitModelForRequest modelForRequest, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         return new PastVisit |  | ||||||
|         { |  | ||||||
|             DestinationCountry = await countries.GetByIdAsync(modelForRequest.DestinationCountryId, cancellationToken), |  | ||||||
|             StartDate = modelForRequest.StartDate, |  | ||||||
|             EndDate = modelForRequest.EndDate |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,17 +0,0 @@ | |||||||
| using Domains.VisaApplicationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Models |  | ||||||
| { |  | ||||||
|     /// Model of <see cref="PastVisit"/> with only name of the destination country |  | ||||||
|     public class PastVisitModel |  | ||||||
|     { |  | ||||||
|         /// <inheritdoc cref="PastVisit.StartDate"/> |  | ||||||
|         public DateTime StartDate { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="PastVisit.EndDate"/> |  | ||||||
|         public DateTime EndDate { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc cref="PastVisit.DestinationCountry"/> |  | ||||||
|         public string DestinationCountry { get; set; } = null!; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| using Domains.VisaApplicationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Models |  | ||||||
| { |  | ||||||
|     /// Model of <see cref="PastVisit"/> with only identifier of country |  | ||||||
|     public class PastVisitModelForRequest |  | ||||||
|     { |  | ||||||
|         /// First day of <see cref="PastVisitModelForRequest"/> |  | ||||||
|         public DateTime StartDate { get; set; } |  | ||||||
|  |  | ||||||
|         /// Last day of <see cref="PastVisitModelForRequest"/> |  | ||||||
|         public DateTime EndDate { get; set; } |  | ||||||
|  |  | ||||||
|         /// Identifier of destination country of <see cref="PastVisitModelForRequest"/> |  | ||||||
|         public Guid DestinationCountryId { get; set; } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -18,7 +18,7 @@ namespace ApplicationLayer.Services.VisaApplications.Models | |||||||
|         /// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/> |         /// <inheritdoc cref="VisaApplication.PermissionToDestCountry"/> | ||||||
|         public PermissionToDestCountry? PermissionToDestCountry { get; set; } |         public PermissionToDestCountry? PermissionToDestCountry { get; set; } | ||||||
|  |  | ||||||
|         public List<PastVisitModel> 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; } | ||||||
|   | |||||||
| @@ -1,17 +1,16 @@ | |||||||
| using ApplicationLayer.Services.VisaApplications.Models; | using Domains.VisaApplicationDomain; | ||||||
| using Domains.VisaApplicationDomain; |  | ||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.VisaApplications.Requests; | namespace ApplicationLayer.Services.VisaApplications.Requests; | ||||||
|  |  | ||||||
| /// Model of visa request from user | /// Model of visa request from user | ||||||
| public record VisaApplicationCreateRequest( | public record VisaApplicationCreateRequest( | ||||||
|     ReentryPermit ReentryPermit, |     ReentryPermit ReentryPermit, | ||||||
|     Guid DestinationCountryId, |     string DestinationCountry, | ||||||
|     VisaCategory VisaCategory, |     VisaCategory VisaCategory, | ||||||
|     bool IsForGroup, |     bool IsForGroup, | ||||||
|     RequestedNumberOfEntries RequestedNumberOfEntries, |     RequestedNumberOfEntries RequestedNumberOfEntries, | ||||||
|     int ValidDaysRequested, |     int ValidDaysRequested, | ||||||
|     PastVisa[] PastVisas, |     PastVisa[] PastVisas, | ||||||
|     PermissionToDestCountry? PermissionToDestCountry, |     PermissionToDestCountry? PermissionToDestCountry, | ||||||
|     PastVisitModelForRequest[] PastVisits |     PastVisit[] PastVisits | ||||||
| ); | ); | ||||||
|   | |||||||
| @@ -1,16 +1,14 @@ | |||||||
| using Domains.LocationDomain; | namespace Domains.ApplicantDomain; | ||||||
|  |  | ||||||
| namespace Domains.ApplicantDomain; |  | ||||||
|  |  | ||||||
| /// Model of address | /// Model of address | ||||||
| /// <remarks>Owned</remarks> | /// <remarks>Owned</remarks> | ||||||
| public class Address | public class Address | ||||||
| { | { | ||||||
|     /// Country part of address |     /// Country part of address | ||||||
|     public Country Country { get; set; } = null!; |     public string Country { get; set; } = null!; | ||||||
|  |  | ||||||
|     /// City part of address |     /// City part of address | ||||||
|     public City City { get; set; } = null!; |     public string City { get; set; } = null!; | ||||||
|  |  | ||||||
|     /// Street part of address |     /// Street part of address | ||||||
|     public string Street { get; set; } = null!; |     public string Street { get; set; } = null!; | ||||||
|   | |||||||
| @@ -1,6 +1,4 @@ | |||||||
| using Domains.LocationDomain; | namespace Domains.ApplicantDomain; | ||||||
|  |  | ||||||
| namespace Domains.ApplicantDomain; |  | ||||||
|  |  | ||||||
| /// Model of an applicant | /// Model of an applicant | ||||||
| public class Applicant : IEntity | public class Applicant : IEntity | ||||||
| @@ -19,11 +17,11 @@ public class Applicant : IEntity | |||||||
|     /// Date of birth of the <see cref="Applicant"/> |     /// Date of birth of the <see cref="Applicant"/> | ||||||
|     public DateTime BirthDate { get; set; } |     public DateTime BirthDate { get; set; } | ||||||
|  |  | ||||||
|     /// <see cref="Country"/> of birth of the <see cref="Applicant"/> |     /// Country of birth of the <see cref="Applicant"/> | ||||||
|     public Country CountryOfBirth { get; set; } = null!; |     public string CountryOfBirth { get; set; } = null!; | ||||||
|  |  | ||||||
|     /// <see cref="City"/> of birth of the <see cref="Applicant"/> |     /// City of birth of the <see cref="Applicant"/> | ||||||
|     public City CityOfBirth { get; set; } = null!; |     public string CityOfBirth { get; set; } = null!; | ||||||
|  |  | ||||||
|     /// Citizenship of <see cref="Applicant"/> |     /// Citizenship of <see cref="Applicant"/> | ||||||
|     public string Citizenship { get; set; } = null!; |     public string Citizenship { get; set; } = null!; | ||||||
|   | |||||||
| @@ -1,17 +0,0 @@ | |||||||
| using System.Text.Json.Serialization; |  | ||||||
|  |  | ||||||
| namespace Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| /// Model of a city |  | ||||||
| public class City : IEntity |  | ||||||
| { |  | ||||||
|     /// Unique identifier of the <see cref="City"/> |  | ||||||
|     public Guid Id { get; private set; } = Guid.NewGuid(); |  | ||||||
|  |  | ||||||
|     /// Name of the city |  | ||||||
|     public string Name { get; set; } = null!; |  | ||||||
|  |  | ||||||
|     /// <see cref="LocationDomain.Country"/> in which the city is located |  | ||||||
|     [JsonIgnore] |  | ||||||
|     public Country Country { get; set; } = null!; |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| namespace Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| /// Model of a country |  | ||||||
| public class Country : IEntity |  | ||||||
| { |  | ||||||
|     /// Unique identifier of the <see cref="Country"/> |  | ||||||
|     public Guid Id { get; private set; } = Guid.NewGuid(); |  | ||||||
|  |  | ||||||
|     /// Name of the country |  | ||||||
|     public string Name { get; set; } = null!; |  | ||||||
|  |  | ||||||
|     /// Located in Schengen area |  | ||||||
|     public bool IsSchengen { get; set; } |  | ||||||
|  |  | ||||||
|     /// List of <see cref="City"/> that country have |  | ||||||
|     public List<City> Cities { get; set; } = null!; |  | ||||||
| } |  | ||||||
| @@ -1,5 +1,4 @@ | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| namespace Domains.VisaApplicationDomain; | namespace Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
| @@ -14,5 +13,5 @@ public class PastVisit | |||||||
|     public DateTime EndDate { get; set; } |     public DateTime EndDate { get; set; } | ||||||
|  |  | ||||||
|     /// Destination country of <see cref="PastVisit"/> |     /// Destination country of <see cref="PastVisit"/> | ||||||
|     public Country DestinationCountry { get; set; } = null!; |     public string DestinationCountry { get; set; } = null!; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using Domains.LocationDomain; |  | ||||||
|  |  | ||||||
| namespace Domains.VisaApplicationDomain; | namespace Domains.VisaApplicationDomain; | ||||||
|  |  | ||||||
| @@ -12,15 +11,12 @@ public class VisaApplication : IEntity | |||||||
|     /// Identifier of the <see cref="Applicant"/> |     /// Identifier of the <see cref="Applicant"/> | ||||||
|     public Guid ApplicantId { get; set; } |     public Guid ApplicantId { get; set; } | ||||||
|  |  | ||||||
|     /// Applicant of <see cref="VisaApplication"/> |  | ||||||
|     public Applicant Applicant { get; set; } = null!; |  | ||||||
|  |  | ||||||
|     /// <inheritdoc cref="Domains.VisaApplicationDomain.ReentryPermit"/> |     /// <inheritdoc cref="Domains.VisaApplicationDomain.ReentryPermit"/> | ||||||
|     /// <remarks>always null if <see cref="Applicant"/> is not a non-resident</remarks> |     /// <remarks>always null if <see cref="Applicant"/> is not a non-resident</remarks> | ||||||
|     public ReentryPermit? ReentryPermit { get; set; } |     public ReentryPermit? ReentryPermit { get; set; } | ||||||
|  |  | ||||||
|     /// <see cref="Country"/> that <see cref="Applicant"/> wants to visit |     /// Country that <see cref="Applicant"/> wants to visit | ||||||
|     public Country DestinationCountry { get; set; } = null!; |     public string DestinationCountry { get; set; } = null!; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// List of <see cref="PastVisa"/> that applicant had before |     /// List of <see cref="PastVisa"/> that applicant had before | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| using Domains; | using Domains; | ||||||
| using Domains.ApplicantDomain; | using Domains.ApplicantDomain; | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Applicants.Configuration; | namespace Infrastructure.Database.Applicants.Configuration; | ||||||
| @@ -9,15 +8,20 @@ public static class AddressConfiguration<T> where T : class, IEntity | |||||||
| { | { | ||||||
|     public static void Configure(OwnedNavigationBuilder<T, Address> entity) |     public static void Configure(OwnedNavigationBuilder<T, Address> entity) | ||||||
|     { |     { | ||||||
|         entity.HasOne(a => a.Country).WithMany().OnDelete(DeleteBehavior.Restrict); |         entity.Property(a => a.Country) | ||||||
|         entity.HasOne(a => a.City).WithMany().OnDelete(DeleteBehavior.Restrict); |  | ||||||
|  |  | ||||||
|         entity.Property(p => p.Street) |  | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(100); |             .HasMaxLength(ConfigurationConstraints.CountryNameLength); | ||||||
|  |  | ||||||
|         entity.Property(p => p.Building) |         entity.Property(a => a.City) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(10); |             .HasMaxLength(ConfigurationConstraints.CityNameLength); | ||||||
|  |  | ||||||
|  |         entity.Property(a => a.Street) | ||||||
|  |             .IsUnicode(false) | ||||||
|  |             .HasMaxLength(ConfigurationConstraints.StreetNameLength); | ||||||
|  |  | ||||||
|  |         entity.Property(a => a.Building) | ||||||
|  |             .IsUnicode(false) | ||||||
|  |             .HasMaxLength(ConfigurationConstraints.BuildingNumberLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,21 +9,27 @@ public class ApplicantConfiguration : IEntityTypeConfiguration<Applicant> | |||||||
| { | { | ||||||
|     public void Configure(EntityTypeBuilder<Applicant> entity) |     public void Configure(EntityTypeBuilder<Applicant> entity) | ||||||
|     { |     { | ||||||
|         entity.OwnsOne(p => p.Name, NameConfiguration<Applicant>.Configure); |         entity.OwnsOne(a => a.Name, NameConfiguration<Applicant>.Configure); | ||||||
|         entity.OwnsOne(p => p.FatherName, NameConfiguration<Applicant>.Configure); |         entity.OwnsOne(a => a.FatherName, NameConfiguration<Applicant>.Configure); | ||||||
|         entity.OwnsOne(p => p.MotherName, NameConfiguration<Applicant>.Configure); |         entity.OwnsOne(a => a.MotherName, NameConfiguration<Applicant>.Configure); | ||||||
|         entity.OwnsOne(p => p.Passport, PassportConfiguration<Applicant>.Configure); |         entity.OwnsOne(a => a.Passport, PassportConfiguration<Applicant>.Configure); | ||||||
|  |  | ||||||
|         entity.HasOne(a => a.CityOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); |  | ||||||
|         entity.HasOne(a => a.CountryOfBirth).WithMany().OnDelete(DeleteBehavior.Restrict); |  | ||||||
|         entity.HasOne<User>().WithOne().HasForeignKey<Applicant>(a => a.UserId); |         entity.HasOne<User>().WithOne().HasForeignKey<Applicant>(a => a.UserId); | ||||||
|  |  | ||||||
|         entity.Property(p => p.Citizenship) |         entity.Property(a => a.Citizenship) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(30); |             .HasMaxLength(ConfigurationConstraints.CitizenshipLength); | ||||||
|  |  | ||||||
|         entity.Property(p => p.CitizenshipByBirth) |         entity.Property(a => a.CitizenshipByBirth) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(30); |             .HasMaxLength(ConfigurationConstraints.CitizenshipLength); | ||||||
|  |  | ||||||
|  |         entity.Property(a => a.CountryOfBirth) | ||||||
|  |             .IsUnicode(false) | ||||||
|  |             .HasMaxLength(ConfigurationConstraints.CountryNameLength); | ||||||
|  |  | ||||||
|  |         entity.Property(a => a.CityOfBirth) | ||||||
|  |             .IsUnicode(false) | ||||||
|  |             .HasMaxLength(ConfigurationConstraints.CityNameLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,14 +10,14 @@ public static class NameConfiguration<T> where T : class, IEntity | |||||||
|     { |     { | ||||||
|         entity.Property(p => p.FirstName) |         entity.Property(p => p.FirstName) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(50); |             .HasMaxLength(ConfigurationConstraints.NameLength); | ||||||
|  |  | ||||||
|         entity.Property(p => p.Surname) |         entity.Property(p => p.Surname) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(50); |             .HasMaxLength(ConfigurationConstraints.NameLength); | ||||||
|  |  | ||||||
|         entity.Property(p => p.Patronymic) |         entity.Property(p => p.Patronymic) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(50); |             .HasMaxLength(ConfigurationConstraints.NameLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,10 +10,10 @@ public static class PassportConfiguration<T> where T : class, IEntity | |||||||
|     { |     { | ||||||
|         entity.Property(p => p.Number) |         entity.Property(p => p.Number) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(20); |             .HasMaxLength(ConfigurationConstraints.PassportNumberLength); | ||||||
|  |  | ||||||
|         entity.Property(p => p.Issuer) |         entity.Property(p => p.Issuer) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(200); |             .HasMaxLength(ConfigurationConstraints.IssuerNameLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,10 +12,10 @@ public class PlaceOfWorkConfiguration : IEntityTypeConfiguration<PlaceOfWork> | |||||||
|  |  | ||||||
|         entity.Property(p => p.Name) |         entity.Property(p => p.Name) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(200); |             .HasMaxLength(ConfigurationConstraints.PlaceOfWorkNameLength); | ||||||
|  |  | ||||||
|         entity.Property(p => p.PhoneNum) |         entity.Property(p => p.PhoneNum) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(20); |             .HasMaxLength(ConfigurationConstraints.PhoneNumberLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,8 +15,6 @@ public sealed class ApplicantsRepository(IGenericReader reader, IGenericWriter w | |||||||
|     protected override IQueryable<Applicant> LoadDomain() |     protected override IQueryable<Applicant> LoadDomain() | ||||||
|     { |     { | ||||||
|         return base.LoadDomain() |         return base.LoadDomain() | ||||||
|             .Include(a => a.CountryOfBirth) |  | ||||||
|             .Include(a => a.CityOfBirth) |  | ||||||
|             .Include(a => a.PlaceOfWork); |             .Include(a => a.PlaceOfWork); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | namespace Infrastructure.Database | ||||||
|  | { | ||||||
|  |     public static class ConfigurationConstraints | ||||||
|  |     { | ||||||
|  |         public const int CityNameLength = 70; | ||||||
|  |         public const int CountryNameLength = 70; | ||||||
|  |         public const int CitizenshipLength = 30; | ||||||
|  |         public const int ReentryPermitNumberLength = 25; | ||||||
|  |         public const int IssuerNameLength = 200; | ||||||
|  |         public const int VisaNameLength = 70; | ||||||
|  |         public const int StreetNameLength = 100; | ||||||
|  |         public const int PlaceOfWorkNameLength = 200; | ||||||
|  |         public const int NameLength = 50; | ||||||
|  |         public const int BuildingNumberLength = 10; | ||||||
|  |         public const int PassportNumberLength = 20; | ||||||
|  |         public const int PhoneNumberLength = 15; | ||||||
|  |         public const int EmailLength = 254; | ||||||
|  |         public const int PasswordLength = 50; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| using Domains.LocationDomain; |  | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; |  | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Locations.Configuration; |  | ||||||
|  |  | ||||||
| public class CityConfiguration : IEntityTypeConfiguration<City> |  | ||||||
| { |  | ||||||
|     public void Configure(EntityTypeBuilder<City> entity) |  | ||||||
|     { |  | ||||||
|         entity.Property(p => p.Name) |  | ||||||
|             .IsUnicode(false) |  | ||||||
|             .HasMaxLength(70); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| using Domains.LocationDomain; |  | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; |  | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Locations.Configuration; |  | ||||||
|  |  | ||||||
| public class CountryConfiguration : IEntityTypeConfiguration<Country> |  | ||||||
| { |  | ||||||
|     public void Configure(EntityTypeBuilder<Country> entity) |  | ||||||
|     { |  | ||||||
|         entity.Property(c => c.Name) |  | ||||||
|             .IsUnicode(false) |  | ||||||
|             .HasMaxLength(70); |  | ||||||
|  |  | ||||||
|         entity.HasIndex(c => c.Name).IsUnique(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| using ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
| using Infrastructure.Database.Generic; |  | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Locations.Repositories.Cities; |  | ||||||
|  |  | ||||||
| public sealed class CitiesRepository(IGenericReader reader, IGenericWriter writer) |  | ||||||
|     : GenericRepository<City>(reader, writer), ICitiesRepository |  | ||||||
| { |  | ||||||
|     protected override IQueryable<City> LoadDomain() |  | ||||||
|     { |  | ||||||
|         return base.LoadDomain().Include(c => c.Country); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Task<City?> ICitiesRepository.GetByNameAsync(Guid countryId, string cityName, CancellationToken cancellationToken) |  | ||||||
|         => LoadDomain().SingleOrDefaultAsync(c => c.Country.Id == countryId && c.Name == cityName, cancellationToken); |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| using ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
| using Infrastructure.Database.Generic; |  | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.Locations.Repositories.Countries; |  | ||||||
|  |  | ||||||
| public sealed class CountriesRepository(IGenericReader reader, IGenericWriter writer) |  | ||||||
|     : GenericRepository<Country>(reader, writer), ICountriesRepository |  | ||||||
| { |  | ||||||
|     protected override IQueryable<Country> LoadDomain() |  | ||||||
|     { |  | ||||||
|         return base.LoadDomain().Include(c => c.Cities); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async Task<Country?> ICountriesRepository.FindByNameAsync(string countryName, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         var result = await LoadDomain().SingleOrDefaultAsync(c => c.Name == countryName, cancellationToken); |  | ||||||
|         return result; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async Task<Country?> ICountriesRepository.FindByIdAsync(Guid id, CancellationToken cancellationToken) |  | ||||||
|     { |  | ||||||
|         var result = await LoadDomain().SingleOrDefaultAsync(c => c.Id == id, cancellationToken); |  | ||||||
|         return result; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -10,13 +10,13 @@ namespace Infrastructure.Database.Users.Configuration | |||||||
|         { |         { | ||||||
|             entity.Property(u => u.Email) |             entity.Property(u => u.Email) | ||||||
|                 .IsUnicode(false) |                 .IsUnicode(false) | ||||||
|                 .HasMaxLength(254); |                 .HasMaxLength(ConfigurationConstraints.EmailLength); | ||||||
|  |  | ||||||
|             entity.HasIndex(u => u.Email).IsUnique(); |             entity.HasIndex(u => u.Email).IsUnique(); | ||||||
|  |  | ||||||
|             entity.Property(u => u.Password) |             entity.Property(u => u.Password) | ||||||
|                 .IsUnicode(false) |                 .IsUnicode(false) | ||||||
|                 .HasMaxLength(50); |                 .HasMaxLength(ConfigurationConstraints.PasswordLength); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,6 +10,6 @@ public static class PastVisaConfiguration<T> where T : class, IEntity | |||||||
|     { |     { | ||||||
|         entity.Property(p => p.Name) |         entity.Property(p => p.Name) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(70); |             .HasMaxLength(ConfigurationConstraints.VisaNameLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| using Domains; | using Domains; | ||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using Microsoft.EntityFrameworkCore; |  | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||||||
|  |  | ||||||
| namespace Infrastructure.Database.VisaApplications.Configuration | namespace Infrastructure.Database.VisaApplications.Configuration | ||||||
| @@ -9,7 +8,9 @@ namespace Infrastructure.Database.VisaApplications.Configuration | |||||||
|     { |     { | ||||||
|         public static void Configure(OwnedNavigationBuilder<T, PastVisit> entity) |         public static void Configure(OwnedNavigationBuilder<T, PastVisit> entity) | ||||||
|         { |         { | ||||||
|             entity.HasOne(p => p.DestinationCountry).WithMany().OnDelete(DeleteBehavior.Restrict); |             entity.Property(pv => pv.DestinationCountry) | ||||||
|  |                 .IsUnicode(false) | ||||||
|  |                 .HasMaxLength(ConfigurationConstraints.CountryNameLength); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,6 +10,6 @@ public static class PermissionToDestCountryConfiguration<T> where T : class, IEn | |||||||
|     { |     { | ||||||
|         entity.Property(p => p.Issuer) |         entity.Property(p => p.Issuer) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(200); |             .HasMaxLength(ConfigurationConstraints.IssuerNameLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,6 +10,6 @@ public static class ReentryPermitConfiguration<T> where T : class, IEntity | |||||||
|     { |     { | ||||||
|         entity.Property(p => p.Number) |         entity.Property(p => p.Number) | ||||||
|             .IsUnicode(false) |             .IsUnicode(false) | ||||||
|             .HasMaxLength(25); |             .HasMaxLength(ConfigurationConstraints.ReentryPermitNumberLength); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| using Domains.VisaApplicationDomain; | using Domains.ApplicantDomain; | ||||||
|  | using Domains.VisaApplicationDomain; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| using Microsoft.EntityFrameworkCore.Metadata.Builders; | using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||||||
|  |  | ||||||
| @@ -11,11 +12,13 @@ public class VisaApplicationConfiguration : IEntityTypeConfiguration<VisaApplica | |||||||
|         entity.OwnsOne(va => va.ReentryPermit, ReentryPermitConfiguration<VisaApplication>.Configure); |         entity.OwnsOne(va => va.ReentryPermit, ReentryPermitConfiguration<VisaApplication>.Configure); | ||||||
|         entity.OwnsOne(va => va.PermissionToDestCountry, PermissionToDestCountryConfiguration<VisaApplication>.Configure); |         entity.OwnsOne(va => va.PermissionToDestCountry, PermissionToDestCountryConfiguration<VisaApplication>.Configure); | ||||||
|         entity.OwnsMany(va => va.PastVisits, PastVisitConfiguration<VisaApplication>.Configure); |         entity.OwnsMany(va => va.PastVisits, PastVisitConfiguration<VisaApplication>.Configure); | ||||||
|         entity.OwnsMany(va => va.PastVisas); |         entity.OwnsMany(va => va.PastVisas, PastVisaConfiguration<VisaApplication>.Configure); | ||||||
|  |  | ||||||
|         entity.HasOne(va => va.DestinationCountry).WithMany().OnDelete(DeleteBehavior.Restrict); |         entity.Property(va => va.DestinationCountry) | ||||||
|  |             .IsUnicode(false) | ||||||
|  |             .HasMaxLength(ConfigurationConstraints.CountryNameLength); | ||||||
|  |  | ||||||
|         entity.HasOne(va => va.Applicant) |         entity.HasOne<Applicant>() | ||||||
|             .WithMany() |             .WithMany() | ||||||
|             .HasForeignKey(va => va.ApplicantId) |             .HasForeignKey(va => va.ApplicantId) | ||||||
|             .IsRequired(); |             .IsRequired(); | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ public sealed class VisaApplicationsRepository(IGenericReader reader, IGenericWr | |||||||
| { | { | ||||||
|     protected override IQueryable<VisaApplication> LoadDomain() |     protected override IQueryable<VisaApplication> LoadDomain() | ||||||
|         => base.LoadDomain() |         => base.LoadDomain() | ||||||
|             .Include(va => va.DestinationCountry) |  | ||||||
|             .Include(va => va.PastVisas) |             .Include(va => va.PastVisas) | ||||||
|             .Include(va => va.PastVisits); |             .Include(va => va.PastVisits); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,13 +1,10 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | using ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
| using ApplicationLayer.Services.Applicants.NeededServices; | using ApplicationLayer.Services.Applicants.NeededServices; | ||||||
| using ApplicationLayer.Services.AuthServices.NeededServices; | using ApplicationLayer.Services.AuthServices.NeededServices; | ||||||
| using ApplicationLayer.Services.Locations.NeededServices; |  | ||||||
| using ApplicationLayer.Services.VisaApplications.NeededServices; | using ApplicationLayer.Services.VisaApplications.NeededServices; | ||||||
| using Infrastructure.Common; | using Infrastructure.Common; | ||||||
| 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.Countries; |  | ||||||
| using Infrastructure.Database.Users.Repositories; | using Infrastructure.Database.Users.Repositories; | ||||||
| using Infrastructure.Database.VisaApplications.Repositories; | using Infrastructure.Database.VisaApplications.Repositories; | ||||||
| using Microsoft.EntityFrameworkCore; | using Microsoft.EntityFrameworkCore; | ||||||
| @@ -36,8 +33,6 @@ public static class DependencyInjection | |||||||
|  |  | ||||||
|         services.AddScoped<IApplicantsRepository, ApplicantsRepository>(); |         services.AddScoped<IApplicantsRepository, ApplicantsRepository>(); | ||||||
|         services.AddScoped<IVisaApplicationsRepository, VisaApplicationsRepository>(); |         services.AddScoped<IVisaApplicationsRepository, VisaApplicationsRepository>(); | ||||||
|         services.AddScoped<ICitiesRepository, CitiesRepository>(); |  | ||||||
|         services.AddScoped<ICountriesRepository, CountriesRepository>(); |  | ||||||
|         services.AddScoped<IUsersRepository, UsersRepository>(); |         services.AddScoped<IUsersRepository, UsersRepository>(); | ||||||
|  |  | ||||||
|         services.AddSingleton<IDateTimeProvider, DateTimeProvider>(); |         services.AddSingleton<IDateTimeProvider, DateTimeProvider>(); | ||||||
|   | |||||||
| @@ -1,53 +0,0 @@ | |||||||
| using ApplicationLayer.Services.Locations.RequestHandlers; |  | ||||||
| using ApplicationLayer.Services.Locations.Requests; |  | ||||||
| using Domains.LocationDomain; |  | ||||||
| using Domains.Users; |  | ||||||
| using Microsoft.AspNetCore.Authorization; |  | ||||||
| using Microsoft.AspNetCore.Mvc; |  | ||||||
| using SchengenVisaApi.Common; |  | ||||||
|  |  | ||||||
| namespace SchengenVisaApi.Controllers |  | ||||||
| { |  | ||||||
|     /// Controller for <see cref="Domains.LocationDomain"/> |  | ||||||
|     [ApiController] |  | ||||||
|     [Route("locations")] |  | ||||||
|     public class LocationsController(ILocationRequestsHandler requestsHandler) : ControllerBase |  | ||||||
|     { |  | ||||||
|         /// Return countries with cities from DB |  | ||||||
|         [HttpGet] |  | ||||||
|         [ProducesResponseType<List<Country>>(StatusCodes.Status200OK)] |  | ||||||
|         public async Task<IActionResult> GetAvailableLocations(CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             return Ok(await requestsHandler.HandleGetRequestAsync(cancellationToken)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// Adds country with cities to DB |  | ||||||
|         /// <remarks>Accessible only for <see cref="Role.Admin"/></remarks> |  | ||||||
|         [HttpPost] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status400BadRequest)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status401Unauthorized)] |  | ||||||
|         [Route("country")] |  | ||||||
|         [Authorize(policy: PolicyConstants.AdminPolicy)] |  | ||||||
|         public async Task<IActionResult> AddCountry(AddCountryRequest request, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             await requestsHandler.AddCountryAsync(request, cancellationToken); |  | ||||||
|             return Ok(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// Updates country with cities in DB |  | ||||||
|         [HttpPut] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status404NotFound)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |  | ||||||
|         [ProducesResponseType(StatusCodes.Status401Unauthorized)] |  | ||||||
|         [Route("country")] |  | ||||||
|         [Authorize(policy: PolicyConstants.AdminPolicy)] |  | ||||||
|         public async Task<IActionResult> UpdateCountry(UpdateCountryRequest request, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             await requestsHandler.UpdateCountryAsync(request, cancellationToken); |  | ||||||
|             return Ok(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,19 +1,18 @@ | |||||||
| using ApplicationLayer.Services.AuthServices.LoginService; | using ApplicationLayer.Services.AuthServices.LoginService; | ||||||
| using ApplicationLayer.Services.AuthServices.RegisterService; | using ApplicationLayer.Services.AuthServices.RegisterService; | ||||||
| using ApplicationLayer.Services.AuthServices.Requests; | using ApplicationLayer.Services.AuthServices.Requests; | ||||||
| using Domains.Users; |  | ||||||
| using Microsoft.AspNetCore.Authorization; | using Microsoft.AspNetCore.Authorization; | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| using SchengenVisaApi.Common; | using SchengenVisaApi.Common; | ||||||
|  |  | ||||||
| namespace SchengenVisaApi.Controllers | namespace SchengenVisaApi.Controllers | ||||||
| { | { | ||||||
|     /// Controller for <see cref="Domains.Users"/> |     ///<summary> Controller for user-auth and registration </summary> | ||||||
|     [ApiController] |     [ApiController] | ||||||
|     [Route("auth")] |     [Route("auth")] | ||||||
|     public class UsersController(IRegisterService registerService, ILoginService loginService) : ControllerBase |     public class UsersController(IRegisterService registerService, ILoginService loginService) : ControllerBase | ||||||
|     { |     { | ||||||
|         /// Adds applicant with user account to DB |         /// <summary> Adds applicant with user account to DB </summary> | ||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |         [ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status409Conflict)] |         [ProducesResponseType(StatusCodes.Status409Conflict)] | ||||||
| @@ -24,8 +23,8 @@ namespace SchengenVisaApi.Controllers | |||||||
|             return Ok(); |             return Ok(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// Adds approving authority with user account to DB |         /// <summary> Adds approving authority with user account to DB </summary> | ||||||
|         /// <remarks>Accessible only for <see cref="Role.Admin"/></remarks> |         ///<remarks> Accessible only for admins </remarks> | ||||||
|         [HttpPost] |         [HttpPost] | ||||||
|         [ProducesResponseType(StatusCodes.Status200OK)] |         [ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status409Conflict)] |         [ProducesResponseType(StatusCodes.Status409Conflict)] | ||||||
| @@ -39,7 +38,7 @@ namespace SchengenVisaApi.Controllers | |||||||
|             return Ok(); |             return Ok(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// Returns JWT-token for authentication |         /// <summary> Returns JWT-token for authentication </summary> | ||||||
|         [HttpGet] |         [HttpGet] | ||||||
|         [ProducesResponseType<string>(StatusCodes.Status200OK)] |         [ProducesResponseType<string>(StatusCodes.Status200OK)] | ||||||
|         [ProducesResponseType(StatusCodes.Status403Forbidden)] |         [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ using System.Security.Claims; | |||||||
| 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; | ||||||
| using Domains.Users; |  | ||||||
| using Domains.VisaApplicationDomain; | using Domains.VisaApplicationDomain; | ||||||
| using Microsoft.AspNetCore.Authorization; | using Microsoft.AspNetCore.Authorization; | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| @@ -10,14 +9,14 @@ using SchengenVisaApi.Common; | |||||||
|  |  | ||||||
| namespace SchengenVisaApi.Controllers; | namespace SchengenVisaApi.Controllers; | ||||||
|  |  | ||||||
| /// Controller for <see cref="Domains.VisaApplicationDomain"/> | /// <summary> Controller for <see cref="Domains.VisaApplicationDomain"/> </summary> | ||||||
| [ApiController] | [ApiController] | ||||||
| [Route("[controller]")] | [Route("[controller]")] | ||||||
| public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : ControllerBase | public class VisaApplicationController(IVisaApplicationRequestsHandler visaApplicationRequestsHandler) : ControllerBase | ||||||
| { | { | ||||||
|     //todo should return only pending applications |     //todo should return only pending applications | ||||||
|     /// Returns all <see cref="Domains.VisaApplicationDomain.VisaApplication"/> from DB |     /// <summary> Returns all applications from DB </summary> | ||||||
|     /// <remarks>Accessible only for <see cref="Role.ApprovingAuthority"/></remarks> |     /// <remarks> Accessible only for approving authorities </remarks> | ||||||
|     [HttpGet] |     [HttpGet] | ||||||
|     [ProducesResponseType<List<VisaApplication>>(StatusCodes.Status200OK)] |     [ProducesResponseType<List<VisaApplication>>(StatusCodes.Status200OK)] | ||||||
|     [ProducesResponseType(StatusCodes.Status403Forbidden)] |     [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
| @@ -29,8 +28,8 @@ public class VisaApplicationController(IVisaApplicationRequestsHandler visaAppli | |||||||
|         return Ok(result); |         return Ok(result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Returns all <see cref="VisaApplication"/> of one applicant |     /// <summary> Returns all applications of one applicant </summary> | ||||||
|     /// <remarks>Returns applications for authorized applicant</remarks> |     /// <remarks> Returns applications of authorized applicant </remarks> | ||||||
|     [HttpGet] |     [HttpGet] | ||||||
|     [ProducesResponseType<List<VisaApplicationModelForApplicant>>(StatusCodes.Status200OK)] |     [ProducesResponseType<List<VisaApplicationModelForApplicant>>(StatusCodes.Status200OK)] | ||||||
|     [ProducesResponseType(StatusCodes.Status403Forbidden)] |     [ProducesResponseType(StatusCodes.Status403Forbidden)] | ||||||
| @@ -45,7 +44,7 @@ public class VisaApplicationController(IVisaApplicationRequestsHandler visaAppli | |||||||
|         return Ok(result); |         return Ok(result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Adds new <see cref="VisaApplication"/> to DB |     /// <summary> Adds new application to DB </summary> | ||||||
|     /// <remarks> Adds application for authorized applicant </remarks> |     /// <remarks> Adds application for authorized applicant </remarks> | ||||||
|     [HttpPost] |     [HttpPost] | ||||||
|     [ProducesResponseType(StatusCodes.Status200OK)] |     [ProducesResponseType(StatusCodes.Status200OK)] | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| using ApplicationLayer.GeneralExceptions; | using ApplicationLayer.GeneralExceptions; | ||||||
| using ApplicationLayer.Services.AuthServices.LoginService.Exceptions; | using ApplicationLayer.Services.AuthServices.LoginService.Exceptions; | ||||||
| using ApplicationLayer.Services.GeneralExceptions; | using ApplicationLayer.Services.GeneralExceptions; | ||||||
| using ApplicationLayer.Services.Locations.RequestHandlers.Exceptions; |  | ||||||
| using Domains; | using Domains; | ||||||
| using Microsoft.AspNetCore.Mvc; | using Microsoft.AspNetCore.Mvc; | ||||||
| using Microsoft.AspNetCore.Mvc.Filters; | using Microsoft.AspNetCore.Mvc.Filters; | ||||||
| @@ -37,16 +36,6 @@ namespace SchengenVisaApi.ExceptionFilters | |||||||
|                         problemDetails.Title = "Already exists"; |                         problemDetails.Title = "Already exists"; | ||||||
|                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; |                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; | ||||||
|                         break; |                         break; | ||||||
|                     case MultipleIdenticalCitiesInCountryException: |  | ||||||
|                         problemDetails.Status = StatusCodes.Status400BadRequest; |  | ||||||
|                         problemDetails.Title = "Can not add cities with one name to one country"; |  | ||||||
|                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; |  | ||||||
|                         break; |  | ||||||
|                     case EntityUsedInDatabaseException: |  | ||||||
|                         problemDetails.Status = StatusCodes.Status409Conflict; |  | ||||||
|                         problemDetails.Title = "entity is used by someone"; |  | ||||||
|                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; |  | ||||||
|                         break; |  | ||||||
|                     default: |                     default: | ||||||
|                         problemDetails.Status = StatusCodes.Status400BadRequest; |                         problemDetails.Status = StatusCodes.Status400BadRequest; | ||||||
|                         problemDetails.Title = "Bad request"; |                         problemDetails.Title = "Bad request"; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user