From 7742a8d62ab13c763ed53cbbcc9089fb8225f94e Mon Sep 17 00:00:00 2001 From: cuqmbr Date: Wed, 10 May 2023 11:55:55 +0300 Subject: [PATCH] refactor: change route search to accept cityId instead of addressId --- Server/Configurations/MapperInitializer.cs | 1 - Server/Controllers/AutomationController.cs | 30 ---- .../VehicleEnrollmentSearchController.cs | 30 ++++ Server/Program.cs | 7 +- Server/Services/AddressManagementService.cs | 4 +- ...e.cs => VehicleEnrollmentSearchService.cs} | 147 +++++++++--------- .../DataTransferObjects/AddressDto.cs | 1 + .../Responses/SearchEnrollmentResponse.cs | 53 +++++++ 8 files changed, 165 insertions(+), 108 deletions(-) delete mode 100644 Server/Controllers/AutomationController.cs create mode 100644 Server/Controllers/VehicleEnrollmentSearchController.cs rename Server/Services/{AutomationService.cs => VehicleEnrollmentSearchService.cs} (62%) create mode 100644 SharedModels/Responses/SearchEnrollmentResponse.cs diff --git a/Server/Configurations/MapperInitializer.cs b/Server/Configurations/MapperInitializer.cs index 3bdbe6d..d542581 100644 --- a/Server/Configurations/MapperInitializer.cs +++ b/Server/Configurations/MapperInitializer.cs @@ -1,4 +1,3 @@ -using System.Dynamic; using AutoMapper; using Server.Models; using SharedModels.DataTransferObjects; diff --git a/Server/Controllers/AutomationController.cs b/Server/Controllers/AutomationController.cs deleted file mode 100644 index 4b164ea..0000000 --- a/Server/Controllers/AutomationController.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Server.Services; - -namespace Server.Controllers; - -[Route("api/[controller]")] -[ApiController] -public class AutomationController : ControllerBase -{ - private readonly AutomationService _automationService; - - public AutomationController(AutomationService automationService) - { - _automationService = automationService; - } - - [HttpGet] - public async Task GetRoute(int from, int to, DateTime date) - { - var result = await _automationService.GetRoute(from, to, date); - - if (!result.isSucceed) - { - return result.actionResult; - } - - return Ok(result.result); - } -} - diff --git a/Server/Controllers/VehicleEnrollmentSearchController.cs b/Server/Controllers/VehicleEnrollmentSearchController.cs new file mode 100644 index 0000000..84a8837 --- /dev/null +++ b/Server/Controllers/VehicleEnrollmentSearchController.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Mvc; +using Server.Services; + +namespace Server.Controllers; + +[Route("api/search")] +[ApiController] +public class VehicleEnrollmentSearchController : ControllerBase +{ + private readonly VehicleEnrollmentSearchService _vehicleEnrollmentSearchService; + + public VehicleEnrollmentSearchController(VehicleEnrollmentSearchService vehicleEnrollmentSearchService) + { + _vehicleEnrollmentSearchService = vehicleEnrollmentSearchService; + } + + [HttpGet] + public async Task GetRoute(int from, int to, DateTime date) + { + var result = await _vehicleEnrollmentSearchService.GetRoute(from, to, date); + + if (!result.isSucceed) + { + return result.actionResult; + } + + return Ok(result.result); + } +} + diff --git a/Server/Program.cs b/Server/Program.cs index ef7ea98..6a41d98 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -56,8 +56,7 @@ services.AddSwaggerGen(options => { }); services.AddCors(options => { - options.AddDefaultPolicy(policy => policy.AllowAnyOrigin() - .AllowAnyHeader().AllowAnyMethod()); + options.AddDefaultPolicy(policy => policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); }); services.AddIdentityCore(options => @@ -146,7 +145,7 @@ services.AddScoped, DataShaper>(); services.AddScoped, SortHelper>(); services.AddScoped, Pager>(); -services.AddScoped(); +services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -170,7 +169,7 @@ if (Convert.ToBoolean(configuration["UseApiExplorer"])) } /* -app.UseHttpsRedirection(); +pp.UseHttpsRedirection(); */ app.UseAuthentication(); diff --git a/Server/Services/AddressManagementService.cs b/Server/Services/AddressManagementService.cs index 05c4d0d..6260d00 100644 --- a/Server/Services/AddressManagementService.cs +++ b/Server/Services/AddressManagementService.cs @@ -153,7 +153,9 @@ public class AddressManagementService : IAddressManagementService } } - var dbAddress = await _dbContext.Addresses.FirstAsync(a => a.Id == address.Id); + var dbAddress = await _dbContext.Addresses.Where(a => a.Id == address.Id) + .Include(a => a.City).ThenInclude(c => c.State) + .ThenInclude(s => s.Country).FirstAsync(); return (true, null, _mapper.Map(dbAddress)); } diff --git a/Server/Services/AutomationService.cs b/Server/Services/VehicleEnrollmentSearchService.cs similarity index 62% rename from Server/Services/AutomationService.cs rename to Server/Services/VehicleEnrollmentSearchService.cs index 5193139..772bc3b 100644 --- a/Server/Services/AutomationService.cs +++ b/Server/Services/VehicleEnrollmentSearchService.cs @@ -4,23 +4,21 @@ using Microsoft.EntityFrameworkCore; using Server.Data; using Server.Helpers; using Server.Models; +using SharedModels.Responses; namespace Server.Services; -public class AutomationService +public class VehicleEnrollmentSearchService { private readonly ApplicationDbContext _dbContext; - private readonly ISortHelper _sortHelper; - public AutomationService(ApplicationDbContext dbContext, - ISortHelper sortHelper) + public VehicleEnrollmentSearchService(ApplicationDbContext dbContext) { _dbContext = dbContext; - _sortHelper = sortHelper; } - public async Task<(bool isSucceed, IActionResult? actionResult, List result)> GetRoute( - int from, int to, DateTime date) + public async Task<(bool isSucceed, IActionResult? actionResult, IList result)> + GetRoute(int fromCityId, int toCityId, DateTime date) { var dbEnrollments = await _dbContext.VehicleEnrollments .Include(ve => ve.Tickets) @@ -36,20 +34,20 @@ public class AutomationService var toBeRemovedEnrollmentsIds = new List(); + // Find routes without transfers + var directEnrollments = new List(); foreach (var e in dbEnrollments) { - if (e.Route.RouteAddresses.Count(ra => ra.AddressId == from) == 0 || - e.Route.RouteAddresses.Count(ra => ra.AddressId == to) == 0) + if (e.Route.RouteAddresses.Count(ra => ra.Address.CityId == fromCityId) == 0 || + e.Route.RouteAddresses.Count(ra => ra.Address.CityId == toCityId) == 0) { continue; } - var fromOrder = e.Route.RouteAddresses.FirstOrDefault(rad => - rad.AddressId == from)?.Order; - var toOrder = e.Route.RouteAddresses.FirstOrDefault(rad => - rad.AddressId == to)?.Order; + var fromOrder = e.Route.RouteAddresses.First(ra => ra.Address.CityId == fromCityId).Order; + var toOrder = e.Route.RouteAddresses.First(ra => ra.Address.CityId == toCityId).Order; if (fromOrder < toOrder) { @@ -65,10 +63,8 @@ public class AutomationService { var routeAddresses = de.Route.RouteAddresses; - var fromOrder = - routeAddresses.First(ra => ra.AddressId == from).Order; - var toOrder = - routeAddresses.First(ra => ra.AddressId == to).Order; + var fromOrder = routeAddresses.First(ra => ra.Address.CityId == fromCityId).Order; + var toOrder = routeAddresses.First(ra => ra.Address.CityId == toCityId).Order; directEnrollments[directEnrollments.IndexOf(de)].Route.RouteAddresses = routeAddresses .OrderBy(ra => ra.Order) @@ -80,18 +76,20 @@ public class AutomationService .DepartureDateTimeUtc = GetDepartureTime(de); } + // Find routes with one transfer + // Find enrollments with departure city var enrollmentsWithFrom = new List(); foreach (var e in dbEnrollments) { - if (e.Route.RouteAddresses.Count(ra => ra.AddressId == from) == 0) + if (e.Route.RouteAddresses.Count(ra => ra.Address.CityId == fromCityId) == 0) { continue; } - if (e.Route.RouteAddresses.Any(ra => ra.AddressId == from)) + if (e.Route.RouteAddresses.Any(ra => ra.Address.CityId == fromCityId)) { enrollmentsWithFrom.Add(e); toBeRemovedEnrollmentsIds.Add(e.Id); @@ -105,25 +103,25 @@ public class AutomationService { var routeAddresses = ef.Route.RouteAddresses; - var fromOrder = - routeAddresses.First(ra => ra.AddressId == from).Order; + var fromOrder = routeAddresses.First(ra => ra.Address.CityId == fromCityId).Order; enrollmentsWithFrom[enrollmentsWithFrom.IndexOf(ef)].Route.RouteAddresses = routeAddresses .OrderBy(ra => ra.Order) .SkipWhile(ra => ra.Order < fromOrder).ToList(); } + // Find enrollments with arrival city var enrollmentsWithTo = new List(); foreach (var e in dbEnrollments) { - if (e.Route.RouteAddresses.Count(ra => ra.AddressId == to) == 0) + if (e.Route.RouteAddresses.Count(ra => ra.Address.CityId == toCityId) == 0) { continue; } - if (e.Route.RouteAddresses.Any(ra => ra.AddressId == to)) + if (e.Route.RouteAddresses.Any(ra => ra.Address.CityId == toCityId)) { enrollmentsWithTo.Add(e); toBeRemovedEnrollmentsIds.Add(e.Id); @@ -137,14 +135,16 @@ public class AutomationService { var routeAddresses = et.Route.RouteAddresses; - var toOrder = - routeAddresses.First(ra => ra.AddressId == to).Order; + var toOrder = routeAddresses.First(ra => ra.Address.CityId == toCityId).Order; enrollmentsWithTo[enrollmentsWithTo.IndexOf(et)].Route.RouteAddresses = routeAddresses .OrderBy(ra => ra.Order) .TakeWhile(ra => ra.Order <= toOrder).ToList(); } + // Find intersection of + // enrollments with only departure city and + // enrollments with only arrival city var oneTransferPath = new List>(); @@ -159,10 +159,13 @@ public class AutomationService etRouteAddresses.Select(x => x.AddressId), x => x.AddressId).FirstOrDefault()?.AddressId; - var toOrder = efRouteAddresses.First(ra => - ra.AddressId == intersectionAddressId).Order; - var fromOrder = etRouteAddresses.First(ra => - ra.AddressId == intersectionAddressId).Order; + if (intersectionAddressId == null) + { + continue; + } + + var toOrder = efRouteAddresses.First(ra => ra.AddressId == intersectionAddressId).Order; + var fromOrder = etRouteAddresses.First(ra => ra.AddressId == intersectionAddressId).Order; enrollmentsWithFrom[enrollmentsWithFrom.IndexOf(ef)].Route.RouteAddresses = efRouteAddresses.OrderBy(ra => ra.Order) @@ -182,69 +185,69 @@ public class AutomationService } } } + + // Combine enrollments with transfers and enrollments without transfers foreach (var directEnrollment in directEnrollments) { oneTransferPath.Add(new List {directEnrollment}); } - var result = new List(); + // Form an object that will be returned + + var result = new SearchEnrollmentResponse(); - int i = 1; foreach (var path in oneTransferPath) { - - var shapedPath = new ExpandoObject(); - var enrollmentGroup = new ExpandoObject(); - + var enrollmentGroup = new EnrollmentGroup(); int j = 1; foreach (var vehicleEnrollment in path) { - var enrollment = new ExpandoObject(); + enrollmentGroup.Enrollments.Add(new FlattenedEnrollment + { + Id = vehicleEnrollment.Id, + + DepartureAddressId = vehicleEnrollment.Route.RouteAddresses.First().AddressId, + DepartureTime = GetDepartureTime(vehicleEnrollment), + DepartureAddressName = vehicleEnrollment.Route.RouteAddresses.First().Address.Name, + DepartureCityName = vehicleEnrollment.Route.RouteAddresses.First().Address.City.Name, + DepartureStateName = vehicleEnrollment.Route.RouteAddresses.First().Address.City.State.Name, + DepartureCountryName = vehicleEnrollment.Route.RouteAddresses.First().Address.City.State.Country.Name, + DepartureAddressFullName = vehicleEnrollment.Route.RouteAddresses.First().Address.GetFullName(), + + ArrivalAddressId = vehicleEnrollment.Route.RouteAddresses.Last().AddressId, + ArrivalTime = GetArrivalTime(vehicleEnrollment), + ArrivalAddressName = vehicleEnrollment.Route.RouteAddresses.Last().Address.Name, + ArrivalCityName = vehicleEnrollment.Route.RouteAddresses.Last().Address.City.Name, + ArrivalStateName = vehicleEnrollment.Route.RouteAddresses.Last().Address.City.State.Name, + ArrivalCountryName = vehicleEnrollment.Route.RouteAddresses.Last().Address.City.State.Country.Name, + ArrivalAddressFullName = vehicleEnrollment.Route.RouteAddresses.Last().Address.GetFullName(), + + Order = j, + + VehicleId = vehicleEnrollment.VehicleId, + VehicleNumber = vehicleEnrollment.Vehicle.Number, + VehicleType = vehicleEnrollment.Vehicle.Type, + + CompanyId = vehicleEnrollment.Vehicle.CompanyId, + CompanyName = vehicleEnrollment.Vehicle.Company.Name + }); - enrollment.TryAdd("id", vehicleEnrollment.Id); - enrollment.TryAdd("departureTime", GetDepartureTime(vehicleEnrollment)); - enrollment.TryAdd("arrivalTime", GetArrivalTime(vehicleEnrollment)); - enrollment.TryAdd("departureAddressName", vehicleEnrollment.Route.RouteAddresses.First().Address.Name); - enrollment.TryAdd("departureAddressFullName", vehicleEnrollment.Route.RouteAddresses.First().Address.GetFullName()); - enrollment.TryAdd("departureAddressId", vehicleEnrollment.Route.RouteAddresses.First().AddressId); - enrollment.TryAdd("arrivalAddressName", vehicleEnrollment.Route.RouteAddresses.Last().Address.Name); - enrollment.TryAdd("arrivalAddressFullName", vehicleEnrollment.Route.RouteAddresses.Last().Address.GetFullName()); - enrollment.TryAdd("arrivalAddressId", vehicleEnrollment.Route.RouteAddresses.Last().AddressId); - enrollment.TryAdd("order", j); - - var vehicle = new ExpandoObject(); - - vehicle.TryAdd("type", vehicleEnrollment.Vehicle.Type); - vehicle.TryAdd("number", vehicleEnrollment.Vehicle.Number); - - enrollment.TryAdd("vehicle", vehicle); - - var company = new ExpandoObject(); - - company.TryAdd("name", vehicleEnrollment.Vehicle.Company.Name); - - enrollment.TryAdd("company", company); - - - - enrollmentGroup.TryAdd($"enrollment{j}", enrollment); - j++; } - enrollmentGroup.TryAdd("totalDuration", GetTotalDuration(path)); - enrollmentGroup.TryAdd("totalCost", GetTotalCost(path)); + enrollmentGroup.Cost = GetTotalCost(path); + enrollmentGroup.Duration = GetTotalDuration(path); - shapedPath.TryAdd($"enrollmentGroup{i}", enrollmentGroup); - result.Add(shapedPath); - - i++; + result.EnrollmentGroups.Add(enrollmentGroup); } - // result = _sortHelper.ApplySort(result[].AsQueryable(), "+cost").ToList(); + if (result.EnrollmentGroups.Count == 0) + { + return (false, new NotFoundResult(), null!); + } - return (true, null, result); + return (true, null, result.EnrollmentGroups); DateTime GetDepartureTime(VehicleEnrollment enrollment) { diff --git a/SharedModels/DataTransferObjects/AddressDto.cs b/SharedModels/DataTransferObjects/AddressDto.cs index be976e5..14203e8 100644 --- a/SharedModels/DataTransferObjects/AddressDto.cs +++ b/SharedModels/DataTransferObjects/AddressDto.cs @@ -36,6 +36,7 @@ public class InCityAddressDto public string Name { get; set; } = null!; public double Latitude { get; set; } public double Longitude { get; set; } + public int CityId { get; set; } } public class CreateAddressInRouteAddress diff --git a/SharedModels/Responses/SearchEnrollmentResponse.cs b/SharedModels/Responses/SearchEnrollmentResponse.cs new file mode 100644 index 0000000..f93a975 --- /dev/null +++ b/SharedModels/Responses/SearchEnrollmentResponse.cs @@ -0,0 +1,53 @@ +namespace SharedModels.Responses; + +public class SearchEnrollmentResponse +{ + public SearchEnrollmentResponse() + { + EnrollmentGroups = new List(); + } + + public IList EnrollmentGroups { get; set; } +} + +public class EnrollmentGroup +{ + public EnrollmentGroup() + { + Enrollments = new List(); + } + + public IList Enrollments { get; set; } + public TimeSpan Duration { get; set; } + public double Cost { get; set; } +} + +public class FlattenedEnrollment +{ + public int Id { get; set; } + + public int DepartureAddressId { get; set; } + public DateTime DepartureTime { get; set; } + public string DepartureAddressName { get; set; } = null!; + public string DepartureCityName { get; set; } = null!; + public string DepartureStateName { get; set; } = null!; + public string DepartureCountryName { get; set; } = null!; + public string DepartureAddressFullName { get; set; } = null!; + + public int ArrivalAddressId { get; set; } + public DateTime ArrivalTime { get; set; } + public string ArrivalAddressName { get; set; } = null!; + public string ArrivalCityName { get; set; } = null!; + public string ArrivalStateName { get; set; } = null!; + public string ArrivalCountryName { get; set; } = null!; + public string ArrivalAddressFullName { get; set; } = null!; + + public int Order { get; set; } + + public int CompanyId { get; set; } + public string CompanyName { get; set; } = null!; + + public int VehicleId { get; set; } + public string VehicleType { get; set; } = null!; + public string VehicleNumber { get; set; } = null!; +} \ No newline at end of file