updating countries
This commit is contained in:
		| @@ -0,0 +1,7 @@ | |||||||
|  | using ApplicationLayer.GeneralExceptions; | ||||||
|  |  | ||||||
|  | namespace Infrastructure.Database.GeneralExceptions | ||||||
|  | { | ||||||
|  |     /// Exception to throw when can't complete some action on entity(delete or something) because it's needed for other entities | ||||||
|  |     public class EntityUsedInDatabaseException(string message) : ApiException(message); | ||||||
|  | } | ||||||
| @@ -3,4 +3,8 @@ using Domains.LocationDomain; | |||||||
|  |  | ||||||
| namespace ApplicationLayer.Services.Locations.NeededServices; | namespace ApplicationLayer.Services.Locations.NeededServices; | ||||||
|  |  | ||||||
| public interface ICitiesRepository : IGenericRepository<City>; | public interface ICitiesRepository : IGenericRepository<City> | ||||||
|  | { | ||||||
|  |     /// Get <see cref="City"/> by name and country identifier | ||||||
|  |     Task<City?> GetByNameAsync(Guid requestId, string existingCity, CancellationToken cancellationToken); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -6,8 +6,8 @@ namespace ApplicationLayer.Services.Locations.NeededServices; | |||||||
| public interface ICountriesRepository : IGenericRepository<Country> | public interface ICountriesRepository : IGenericRepository<Country> | ||||||
| { | { | ||||||
|     /// Gets country by name |     /// Gets country by name | ||||||
|     /// <param name="countryName">Name of country to seek</param> |     Task<Country?> FindByNameAsync(string countryName, CancellationToken cancellationToken); | ||||||
|     /// <param name="cancellationToken">Cancellation Token</param> |  | ||||||
|     /// <returns>Country or null if not found</returns> |     /// Gets country by identifier | ||||||
|     Task<Country?> FindByName(string countryName, CancellationToken cancellationToken); |     Task<Country?> FindByIdAsync(Guid id, CancellationToken cancellationToken); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | using Infrastructure.Database.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"); | ||||||
|  | } | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | using Domains.LocationDomain; | ||||||
|  | using Infrastructure.Database.GeneralExceptions; | ||||||
|  |  | ||||||
|  | namespace ApplicationLayer.Services.Locations.RequestHandlers.Exceptions | ||||||
|  | { | ||||||
|  |     public class CountryNotFoundException(string countryName) : EntityNotFoundException<Country>($"Country {countryName} is not supported."); | ||||||
|  | } | ||||||
| @@ -10,7 +10,10 @@ namespace ApplicationLayer.Services.Locations.RequestHandlers | |||||||
|         /// <returns>List of available countries</returns> |         /// <returns>List of available countries</returns> | ||||||
|         Task<List<Country>> HandleGetRequestAsync(CancellationToken cancellationToken); |         Task<List<Country>> HandleGetRequestAsync(CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|         /// Handles add country requests |         /// Handles <see cref="AddCountryRequest"/> | ||||||
|         Task AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken); |         Task AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken); | ||||||
|  |  | ||||||
|  |         /// Handles <see cref="UpdateCountryRequest"/> | ||||||
|  |         Task UpdateCountryAsync(UpdateCountryRequest request, CancellationToken cancellationToken); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| using ApplicationLayer.InfrastructureServicesInterfaces; | using ApplicationLayer.InfrastructureServicesInterfaces; | ||||||
|  | using ApplicationLayer.Services.Applicants.NeededServices; | ||||||
| using ApplicationLayer.Services.Locations.NeededServices; | using ApplicationLayer.Services.Locations.NeededServices; | ||||||
| using ApplicationLayer.Services.Locations.RequestHandlers.Exceptions; | using ApplicationLayer.Services.Locations.RequestHandlers.Exceptions; | ||||||
| using ApplicationLayer.Services.Locations.Requests; | using ApplicationLayer.Services.Locations.Requests; | ||||||
| @@ -7,7 +8,11 @@ using Domains.LocationDomain; | |||||||
| namespace ApplicationLayer.Services.Locations.RequestHandlers | namespace ApplicationLayer.Services.Locations.RequestHandlers | ||||||
| { | { | ||||||
|     /// <inheritdoc cref="ILocationRequestsHandler"/> |     /// <inheritdoc cref="ILocationRequestsHandler"/> | ||||||
|     public class LocationRequestsHandler(ICountriesRepository countries, IUnitOfWork unitOfWork) : ILocationRequestsHandler |     public class LocationRequestsHandler( | ||||||
|  |         ICountriesRepository countries, | ||||||
|  |         ICitiesRepository cities, | ||||||
|  |         IApplicantsRepository applicants, | ||||||
|  |         IUnitOfWork unitOfWork) : ILocationRequestsHandler | ||||||
|     { |     { | ||||||
|         async Task<List<Country>> ILocationRequestsHandler.HandleGetRequestAsync(CancellationToken cancellationToken) |         async Task<List<Country>> ILocationRequestsHandler.HandleGetRequestAsync(CancellationToken cancellationToken) | ||||||
|         { |         { | ||||||
| @@ -16,7 +21,7 @@ namespace ApplicationLayer.Services.Locations.RequestHandlers | |||||||
|  |  | ||||||
|         async Task ILocationRequestsHandler.AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken) |         async Task ILocationRequestsHandler.AddCountryAsync(AddCountryRequest request, CancellationToken cancellationToken) | ||||||
|         { |         { | ||||||
|             if (await countries.FindByName(request.CountryName, cancellationToken) is not null) |             if (await countries.FindByNameAsync(request.CountryName, cancellationToken) is not null) | ||||||
|             { |             { | ||||||
|                 throw new CountryAlreadyExists(request.CountryName); |                 throw new CountryAlreadyExists(request.CountryName); | ||||||
|             } |             } | ||||||
| @@ -38,5 +43,49 @@ namespace ApplicationLayer.Services.Locations.RequestHandlers | |||||||
|  |  | ||||||
|             await unitOfWork.SaveAsync(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); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,4 @@ | |||||||
|  | namespace ApplicationLayer.Services.Locations.Requests | ||||||
|  | { | ||||||
|  |     public record UpdateCountryRequest(Guid Id, string CountryName, bool IsSchengen, string[] Cities); | ||||||
|  | } | ||||||
| @@ -12,4 +12,7 @@ public sealed class CitiesRepository(IGenericReader reader, IGenericWriter write | |||||||
|     { |     { | ||||||
|         return base.LoadDomain().Include(c => c.Country); |         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); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,9 +13,15 @@ public sealed class CountriesRepository(IGenericReader reader, IGenericWriter wr | |||||||
|         return base.LoadDomain().Include(c => c.Cities); |         return base.LoadDomain().Include(c => c.Cities); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async Task<Country?> ICountriesRepository.FindByName(string countryName, CancellationToken cancellationToken) |     async Task<Country?> ICountriesRepository.FindByNameAsync(string countryName, CancellationToken cancellationToken) | ||||||
|     { |     { | ||||||
|         var result = await LoadDomain().SingleOrDefaultAsync(c => c.Name == countryName, cancellationToken); |         var result = await LoadDomain().SingleOrDefaultAsync(c => c.Name == countryName, cancellationToken); | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async Task<Country?> ICountriesRepository.FindByIdAsync(Guid id, CancellationToken cancellationToken) | ||||||
|  |     { | ||||||
|  |         var result = await LoadDomain().SingleOrDefaultAsync(c => c.Id == id, cancellationToken); | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ namespace SchengenVisaApi.Controllers | |||||||
| { | { | ||||||
|     /// Controller for <see cref="Domains.LocationDomain"/> |     /// Controller for <see cref="Domains.LocationDomain"/> | ||||||
|     [ApiController] |     [ApiController] | ||||||
|     [Route("countries")] |     [Route("locations")] | ||||||
|     public class LocationsController(ILocationRequestsHandler requestsHandler) : ControllerBase |     public class LocationsController(ILocationRequestsHandler requestsHandler) : ControllerBase | ||||||
|     { |     { | ||||||
|         /// Return countries with cities from DB |         /// Return countries with cities from DB | ||||||
| @@ -35,5 +35,19 @@ namespace SchengenVisaApi.Controllers | |||||||
|             await requestsHandler.AddCountryAsync(request, cancellationToken); |             await requestsHandler.AddCountryAsync(request, cancellationToken); | ||||||
|             return Ok(); |             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(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -42,6 +42,11 @@ namespace SchengenVisaApi.ExceptionFilters | |||||||
|                         problemDetails.Title = "Can not add cities with one name to one country"; |                         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"; |                         problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; | ||||||
|                         break; |                         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