diff --git a/BookingMicroservice/Clients/FlightServiceClient.cs b/BookingMicroservice/Clients/FlightServiceClient.cs index 4d54fd5bd9ce1231b7bafdecc5f2dab1d49c7771..a67d1e3ce543cc3eac7803664e13e87a3c2b2660 100644 --- a/BookingMicroservice/Clients/FlightServiceClient.cs +++ b/BookingMicroservice/Clients/FlightServiceClient.cs @@ -1,4 +1,6 @@ -namespace BookingMicroservice.Clients +using BookingMicroservice.Models; + +namespace BookingMicroservice.Clients { public class FlightServiceClient : IFlightServiceClient { @@ -27,5 +29,10 @@ return await httpClient.PutAsync($"{SEAT_API_PATH}/{seatId}", null); } + public async Task<HttpResponseMessage> GetFlightsByIdAsync(FlightIdCollection flightIdCollection) + { + return await httpClient.PostAsJsonAsync($"{FLIGHT_API_PATH}/byIds", flightIdCollection); + } + } } diff --git a/BookingMicroservice/Clients/IFlightServiceClient.cs b/BookingMicroservice/Clients/IFlightServiceClient.cs index c3e9dcb075454b975abd7927b37979c33056ba96..70bbd25a6a412cec5f363fc0cd8e4de13de87077 100644 --- a/BookingMicroservice/Clients/IFlightServiceClient.cs +++ b/BookingMicroservice/Clients/IFlightServiceClient.cs @@ -1,9 +1,12 @@ -namespace BookingMicroservice.Clients +using BookingMicroservice.Models; + +namespace BookingMicroservice.Clients { public interface IFlightServiceClient { Task<HttpResponseMessage> GetFlightCapacityAsync(int flightId, int classType); Task<HttpResponseMessage> IsSeatAvailableAsync(int seatId); Task<HttpResponseMessage> BookSeatAsync(int seatId); + Task<HttpResponseMessage> GetFlightsByIdAsync(FlightIdCollection flightIdCollection); } } diff --git a/BookingMicroservice/Controllers/BookingController.cs b/BookingMicroservice/Controllers/BookingController.cs index de800b69a4e0fbdae5b598ed496a012cddd9d6ed..a8aabdeffd43c409782b18f03074583cd54cbca2 100644 --- a/BookingMicroservice/Controllers/BookingController.cs +++ b/BookingMicroservice/Controllers/BookingController.cs @@ -87,5 +87,44 @@ namespace BookingMicroservice.Controllers return Ok(new { BookedSeat = false, Message = exception.Message }); } } + + [Authorize] + [HttpGet("upcoming")] + public async Task<IActionResult> GetUpcomingFlightBookings() + { + string? userIdValue = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (!int.TryParse(userIdValue, out int userId)) + return BadRequest("Unable to get User Id from Token"); + + try + { + IEnumerable<FlightBookingInfo> flights = await reservationComplianceService.TryGetUpcomingFlightsAsync(userId); + return Ok(flights); + } + catch(InvalidOperationException exception) + { + return BadRequest(exception.Message); + } + } + + [Authorize] + [HttpGet("history")] + public async Task<IActionResult> GetPreviousFlightBookings() + { + string? userIdValue = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (!int.TryParse(userIdValue, out int userId)) + return BadRequest("Unable to get User Id from Token"); + + try + { + IEnumerable<FlightBookingInfo> flights = await reservationComplianceService.TryGetPreviousFlightsAsync(userId); + return Ok(flights); + } + catch (InvalidOperationException exception) + { + return BadRequest(exception.Message); + } + } + } } diff --git a/BookingMicroservice/Models/Booking.cs b/BookingMicroservice/Models/Booking.cs index 61eaa3e0fb7e3a44e44ef47ab18df4ea39ca8b0e..d9c9ac6dd68211eb941995b0203d0a0adc6cc6ae 100644 --- a/BookingMicroservice/Models/Booking.cs +++ b/BookingMicroservice/Models/Booking.cs @@ -23,10 +23,4 @@ SeatId = seatId; } } - - public enum BookingClass - { - BUSINESS = 0, - ECONOMY = 1 - } } diff --git a/BookingMicroservice/Models/BookingClass.cs b/BookingMicroservice/Models/BookingClass.cs new file mode 100644 index 0000000000000000000000000000000000000000..80b20fb540af8def2aeb51d5f7759a8eadf070d2 --- /dev/null +++ b/BookingMicroservice/Models/BookingClass.cs @@ -0,0 +1,8 @@ +namespace BookingMicroservice.Models +{ + public enum BookingClass + { + BUSINESS = 0, + ECONOMY = 1 + } +} diff --git a/BookingMicroservice/Models/Flight.cs b/BookingMicroservice/Models/Flight.cs new file mode 100644 index 0000000000000000000000000000000000000000..441926bd6a383cd4c24c7950b32feecf892577ce --- /dev/null +++ b/BookingMicroservice/Models/Flight.cs @@ -0,0 +1,12 @@ +namespace BookingMicroservice.Models +{ + public class Flight + { + public int Id { get; set; } + public int AirlineId { get; set; } + public string Origin { get; set; } + public string Destination { get; set; } + public DateTime DepartureTime { get; set; } + public DateTime ArrivalTime { get; set; } + } +} diff --git a/BookingMicroservice/Models/FlightBookingInfo.cs b/BookingMicroservice/Models/FlightBookingInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..32c31dc22cbc3308ec656dd223a7df9bf95b31d0 --- /dev/null +++ b/BookingMicroservice/Models/FlightBookingInfo.cs @@ -0,0 +1,14 @@ +namespace BookingMicroservice.Models +{ + public class FlightBookingInfo + { + public Flight Flight { get; set; } + public Booking Booking { get; set; } + + public FlightBookingInfo(Flight flight, Booking booking) + { + Flight = flight; + Booking = booking; + } + } +} diff --git a/BookingMicroservice/Models/FlightIdCollection.cs b/BookingMicroservice/Models/FlightIdCollection.cs new file mode 100644 index 0000000000000000000000000000000000000000..bf39f59d9d8bfe6333caa8c9423d84d7b44c4478 --- /dev/null +++ b/BookingMicroservice/Models/FlightIdCollection.cs @@ -0,0 +1,8 @@ +namespace BookingMicroservice.Models +{ + public class FlightIdCollection + { + public required List<int> FlightIds { get; set; } + + } +} diff --git a/BookingMicroservice/Models/FlightResponseWrapper.cs b/BookingMicroservice/Models/FlightResponseWrapper.cs new file mode 100644 index 0000000000000000000000000000000000000000..07b804e1008fb451e79f5e3077ec5eba5e74a5d4 --- /dev/null +++ b/BookingMicroservice/Models/FlightResponseWrapper.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace BookingMicroservice.Models +{ + public class FlightResponseWrapper + { + [JsonPropertyName("$values")] + public List<Flight> Values { get; set; } + } +} diff --git a/BookingMicroservice/Services/IReservationComplianceService.cs b/BookingMicroservice/Services/IReservationComplianceService.cs index 7f82720510a1f07e8016add0940502dd22bf822c..a7ad5feacc4aaca948dc50c360f7f7623c8b87c0 100644 --- a/BookingMicroservice/Services/IReservationComplianceService.cs +++ b/BookingMicroservice/Services/IReservationComplianceService.cs @@ -6,6 +6,7 @@ namespace BookingMicroservice.Services { Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId); Task TryBookSeatAsync(int bookingId, int seatId); - + Task<IEnumerable<FlightBookingInfo>> TryGetUpcomingFlightsAsync(int userId); + Task<IEnumerable<FlightBookingInfo>> TryGetPreviousFlightsAsync(int userId); } } diff --git a/BookingMicroservice/Services/ReservationComplianceService.cs b/BookingMicroservice/Services/ReservationComplianceService.cs index df3f6a6effa87f3aa15568b52b339ec3456a81fb..ab80ec322556c4d10f6655ac543503f29668be55 100644 --- a/BookingMicroservice/Services/ReservationComplianceService.cs +++ b/BookingMicroservice/Services/ReservationComplianceService.cs @@ -1,6 +1,8 @@ using BookingMicroservice.Clients; using BookingMicroservice.Exceptions; using BookingMicroservice.Models; +using System.Linq; +using System.Text.Json; namespace BookingMicroservice.Services { @@ -76,5 +78,52 @@ namespace BookingMicroservice.Services bookingService.UpdateBooking(bookingId, seatId); } + public async Task<IEnumerable<FlightBookingInfo>> TryGetUpcomingFlightsAsync(int userId) + { + return await GetFlightsAsync(userId, true); + } + + public async Task<IEnumerable<FlightBookingInfo>> TryGetPreviousFlightsAsync(int userId) + { + return await GetFlightsAsync(userId, false); + } + + private async Task<IEnumerable<FlightBookingInfo>> GetFlightsAsync(int userId, bool isUpcoming) + { + List<Booking> bookings = bookingService.GetBookings(userId: userId); + List<int> flightIds = bookings.Select(booking => booking.FlightId).ToList(); + FlightIdCollection flightIdCollection = new FlightIdCollection { FlightIds = flightIds }; + + HttpResponseMessage flightsResponse = await flightServiceClient.GetFlightsByIdAsync(flightIdCollection); + if (!flightsResponse.IsSuccessStatusCode) + throw new InvalidOperationException("Could not retrieve flights."); + + string flightsString = await flightsResponse.Content.ReadAsStringAsync(); + FlightResponseWrapper? flightResponse = JsonSerializer.Deserialize<FlightResponseWrapper>(flightsString, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + if (flightResponse?.Values == null) + throw new InvalidOperationException("Deserialization of flights failed."); + + List<Flight> flights = flightResponse.Values; + + DateTime comparisonTime = DateTime.UtcNow; + IEnumerable<Flight> filteredFlights = isUpcoming + ? flights.Where(flight => flight.DepartureTime > comparisonTime) + : flights.Where(flight => flight.DepartureTime <= comparisonTime); + + List<FlightBookingInfo> result = filteredFlights.Select(flight => + { + Booking? matchingBooking = bookings.FirstOrDefault(booking => booking.FlightId == flight.Id); + if (matchingBooking == null) + throw new InvalidOperationException($"No booking found for flight ID {flight.Id}."); + + return new FlightBookingInfo(flight, matchingBooking); + + }).ToList(); + + return result; + } + + } + } diff --git a/FlightMicroservice/Controllers/FlightController.cs b/FlightMicroservice/Controllers/FlightController.cs index 2bd55a2cf7155ba0bfbb609ac35ec4da29e47062..5ab973f5631279baeb86782eba3b05e8ee1e20e6 100644 --- a/FlightMicroservice/Controllers/FlightController.cs +++ b/FlightMicroservice/Controllers/FlightController.cs @@ -78,6 +78,16 @@ namespace FlightMicroservice.Controllers return Ok(seats); } + [HttpPost("byIds")] + public IActionResult GetFlightsByIds([FromBody] FlightIdCollection flightIdCollection) + { + List<Flight> flights = flightService.GetFlightsByIds(flightIdCollection.FlightIds); + if (flights == null) + return NotFound(); + + return Ok(flights); + } + } } diff --git a/FlightMicroservice/Models/FlightIdCollection.cs b/FlightMicroservice/Models/FlightIdCollection.cs new file mode 100644 index 0000000000000000000000000000000000000000..03b09b6d02b98fe0b517ccb0e41652a4ef2acf10 --- /dev/null +++ b/FlightMicroservice/Models/FlightIdCollection.cs @@ -0,0 +1,7 @@ +namespace FlightMicroservice.Models +{ + public class FlightIdCollection + { + public required List<int> FlightIds { get; set; } + } +} diff --git a/FlightMicroservice/Services/FlightService.cs b/FlightMicroservice/Services/FlightService.cs index c849e71a99d8f6deb83d068773de401b302fcfba..5122bf6fa14f111d0615dd6e7b41926ab252679f 100644 --- a/FlightMicroservice/Services/FlightService.cs +++ b/FlightMicroservice/Services/FlightService.cs @@ -80,6 +80,14 @@ namespace FlightMicroservice.Services .ToList(); } + public List<Flight> GetFlightsByIds(List<int> ids) + { + return dbContext.Flights + .Where(flight => ids.Contains(flight.Id)) + .ToList(); + } + + private void InitializeSeatsForFlight(Flight flight) { int businessRows = flight.BusinessCapacity / Flight.BUSINESS_SEATS_PER_ROW; diff --git a/FlightMicroservice/Services/IFlightService.cs b/FlightMicroservice/Services/IFlightService.cs index 4dad71b46f0b9372e243485b29eef0d166634678..b9fe6f05b1894df17fc024ca556c3b7828ff9d2b 100644 --- a/FlightMicroservice/Services/IFlightService.cs +++ b/FlightMicroservice/Services/IFlightService.cs @@ -9,5 +9,6 @@ namespace FlightMicroservice.Services Flight CreateFlight(int airlineId, string origin, string destination, DateTime departureTime, DateTime arrivalTime, int economyCapacity, int businessCapacity, decimal economyPrice, decimal businessPrice); bool RemoveFlight(int flightId); List<Seat> GetSeatsByFlightId(int flightId); + List<Flight> GetFlightsByIds(List<int> ids); } } diff --git a/GatewayAPI/Clients/BookingService/BookingServiceClient.cs b/GatewayAPI/Clients/BookingService/BookingServiceClient.cs index dab63de5d0387d0608ea5710ff98cd180b622299..be1534f6625a2bd965338ee04da172178c0d95c1 100644 --- a/GatewayAPI/Clients/BookingService/BookingServiceClient.cs +++ b/GatewayAPI/Clients/BookingService/BookingServiceClient.cs @@ -47,5 +47,16 @@ namespace GatewayAPI.Clients.BookingService } + public Task<HttpResponseMessage> GetUpcomingFlightBookingsAsync() + { + return httpClient.GetAsync($"{API_PATH}/upcoming"); + } + + public Task<HttpResponseMessage> GetPreviousFlightBookingsAsync() + { + return httpClient.GetAsync($"{API_PATH}/history"); + } + + } } diff --git a/GatewayAPI/Clients/BookingService/IBookingServiceClient.cs b/GatewayAPI/Clients/BookingService/IBookingServiceClient.cs index 9b4d6b244c135dc5e08033893f571618d105ae0f..be2db11631d06c73ce80fe82ada5f986c71129a9 100644 --- a/GatewayAPI/Clients/BookingService/IBookingServiceClient.cs +++ b/GatewayAPI/Clients/BookingService/IBookingServiceClient.cs @@ -7,5 +7,8 @@ namespace GatewayAPI.Clients.BookingService Task<HttpResponseMessage> GetBookingAsync(int id); Task<HttpResponseMessage> GetBookingsAsync(int? flightId = null, int? userId = null, int? bookingClass = null); Task<HttpResponseMessage> MakeBookingAsync(BookingCreation bookingModel); - Task<HttpResponseMessage> UpdateBookingAsync(int bookindId, BookingUpdate bookingModel); } + Task<HttpResponseMessage> UpdateBookingAsync(int bookindId, BookingUpdate bookingModel); + Task<HttpResponseMessage> GetUpcomingFlightBookingsAsync(); + Task<HttpResponseMessage> GetPreviousFlightBookingsAsync(); + } } diff --git a/GatewayAPI/Controllers/BookingController.cs b/GatewayAPI/Controllers/BookingController.cs index 3828149606d8c81453d89723f06c10c1992bd4e4..b6ce381f4239cc4f86ae459d3bdc98b757d63e12 100644 --- a/GatewayAPI/Controllers/BookingController.cs +++ b/GatewayAPI/Controllers/BookingController.cs @@ -43,5 +43,19 @@ namespace GatewayAPI.Controllers HttpResponseMessage response = await bookingServiceClient.UpdateBookingAsync(id, bookingUpdateModel); return new HttpResponseMessageResult(response); } + + [HttpGet("upcoming")] + public async Task<IActionResult> GetUpcomingFlightBookings() + { + HttpResponseMessage response = await bookingServiceClient.GetUpcomingFlightBookingsAsync(); + return new HttpResponseMessageResult(response); + } + + [HttpGet("history")] + public async Task<IActionResult> GetPreviousFlightBookings() + { + HttpResponseMessage response = await bookingServiceClient.GetPreviousFlightBookingsAsync(); + return new HttpResponseMessageResult(response); + } } }