From 462a7b3e8484dcf45cbb7a7ae27b1a0a912989c0 Mon Sep 17 00:00:00 2001 From: Mouaz Abdelsamad <ma03081@surrey.ac.uk> Date: Fri, 3 May 2024 01:09:51 +0100 Subject: [PATCH] improvements and bug fixes --- .env | 8 +- .../Controllers/BookingController.cs | 7 +- .../Services/ReservationComplianceService.cs | 4 +- Database/{InitTables.sql => 1-InitTables.sql} | 0 Database/2-DefaultValues.sql | 78 +++++++++++++++++++ .../Controllers/FlightController.cs | 2 +- GatewayAPI/Program.cs | 13 +--- GatewayAPI/ServiceCollectionExtensions.cs | 17 ++++ GatewayAPI/appsettings.json | 3 + .../CustomerBookings/CustomerBookings.tsx | 2 +- .../FlightCreationForm/FlightCreationForm.tsx | 10 +++ client/src/components/Header/Header.tsx | 2 +- .../components/PaymentForm/PaymentForm.tsx | 2 +- .../src/services/BookingView/BookingView.ts | 22 +++--- .../CustomerBookings/CustomerBookings.ts | 5 +- docker-compose.yml | 1 + 16 files changed, 135 insertions(+), 41 deletions(-) rename Database/{InitTables.sql => 1-InitTables.sql} (100%) create mode 100644 Database/2-DefaultValues.sql diff --git a/.env b/.env index 28e4f23..b493772 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ # Image settings -IMAGE_TAG=0.0.1 +IMAGE_TAG=latest MYSQL_IMAGE_TAG=8.0 @@ -10,12 +10,6 @@ DB_USER=user DB_PASSWORD=user DB_CHARSET=utf8mb4 -# Keeping these for dev purposes, will remove at the end -#DB_PORT=3308 -#DB_NAME=AspNetCoreDb -#DB_USER=root -#DB_PASSWORD= -#DB_CHARSET=utf8mb4 # Service ports USER_MICROSERVICE_PORT=5089 diff --git a/BookingMicroservice/Controllers/BookingController.cs b/BookingMicroservice/Controllers/BookingController.cs index 0a2584e..97e4acf 100644 --- a/BookingMicroservice/Controllers/BookingController.cs +++ b/BookingMicroservice/Controllers/BookingController.cs @@ -20,14 +20,11 @@ namespace BookingMicroservice.Controllers private readonly IBookingService bookingService; private readonly IStripeService stripeService; - private readonly IConfiguration configuration; - - public BookingController(IReservationComplianceService reservationComplianceService, IBookingService bookingService, IStripeService stripeService, IConfiguration configuration) + public BookingController(IReservationComplianceService reservationComplianceService, IBookingService bookingService, IStripeService stripeService) { this.reservationComplianceService = reservationComplianceService; this.bookingService = bookingService; this.stripeService = stripeService; - this.configuration = configuration; } [Authorize] @@ -144,7 +141,7 @@ namespace BookingMicroservice.Controllers [Authorize] [HttpPost("create-payment-intent")] - public async Task<IActionResult> CreatePaymentIntent([FromBody] PaymentIntentCreateRequest request) + public IActionResult CreatePaymentIntent([FromBody] PaymentIntentCreateRequest request) { var paymentIntentService = new PaymentIntentService(); var paymentIntent = paymentIntentService.Create(new PaymentIntentCreateOptions diff --git a/BookingMicroservice/Services/ReservationComplianceService.cs b/BookingMicroservice/Services/ReservationComplianceService.cs index ab80ec3..b922d42 100644 --- a/BookingMicroservice/Services/ReservationComplianceService.cs +++ b/BookingMicroservice/Services/ReservationComplianceService.cs @@ -22,7 +22,9 @@ namespace BookingMicroservice.Services public async Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId) { - HttpResponseMessage capacityResponse = await flightServiceClient.GetFlightCapacityAsync(flightId, (int)bookingClass); + int bookingClassValue = BookingClass.BUSINESS == bookingClass ? 0 : 1; + + HttpResponseMessage capacityResponse = await flightServiceClient.GetFlightCapacityAsync(flightId, bookingClassValue); if (!capacityResponse.IsSuccessStatusCode) throw new InvalidOperationException("Could not retrieve flight capacity."); diff --git a/Database/InitTables.sql b/Database/1-InitTables.sql similarity index 100% rename from Database/InitTables.sql rename to Database/1-InitTables.sql diff --git a/Database/2-DefaultValues.sql b/Database/2-DefaultValues.sql new file mode 100644 index 0000000..59531e5 --- /dev/null +++ b/Database/2-DefaultValues.sql @@ -0,0 +1,78 @@ +INSERT INTO Users (Username, Email, PasswordHash, Type) VALUES +('SkyHigh Airlines', 'skyHigh@gmail.com', 'AQAAAAIAAYagAAAAEL9Xj4ZjCgTc/w0XbnjHE63KPvhYmJdTZV9k570Bw0QuPsrupU8EGS7kT7hUoGZdbg==', 1); + +INSERT INTO Flights (AirlineId, Origin, Destination, DepartureTime, ArrivalTime, EconomyCapacity, BusinessCapacity, EconomyPrice, BusinessPrice) VALUES +(1, 'London Heathrow', 'Liverpool', '2024-07-15 08:00:00', '2024-07-15 12:00:00', 24, 8, 200.00, 500.00), +(1, 'London Heathrow', 'Glasgow', '2024-07-15 08:00:00', '2024-07-15 12:00:00', 24, 8, 150.00, 350.00); + + +INSERT INTO Seats (FlightId, SeatNumber, ClassType, IsAvailable) VALUES +(1, '1A', 0, 1), +(1, '1B', 0, 1), +(1, '1C', 0, 1), +(1, '1D', 0, 1), +(1, '2A', 0, 1), +(1, '2B', 0, 1), +(1, '2C', 0, 1), +(1, '2D', 0, 1), +(2, '1A', 0, 1), +(2, '1B', 0, 1), +(2, '1C', 0, 1), +(2, '1D', 0, 1), +(2, '2A', 0, 1), +(2, '2B', 0, 1), +(2, '2C', 0, 1), +(2, '2D', 0, 1); + +INSERT INTO Seats (FlightId, SeatNumber, ClassType, IsAvailable) VALUES +(1, '3A', 1, 1), +(1, '3B', 1, 1), +(1, '3C', 1, 1), +(1, '3D', 1, 1), +(1, '3E', 1, 1), +(1, '3F', 1, 1), +(1, '4A', 1, 1), +(1, '4B', 1, 1), +(1, '4C', 1, 1), +(1, '4D', 1, 1), +(1, '4E', 1, 1), +(1, '4F', 1, 1), +(1, '5A', 1, 1), +(1, '5B', 1, 1), +(1, '5C', 1, 1), +(1, '5D', 1, 1), +(1, '5E', 1, 1), +(1, '5F', 1, 1), +(1, '6A', 1, 1), +(1, '6B', 1, 1), +(1, '6C', 1, 1), +(1, '6D', 1, 1), +(1, '6E', 1, 1), +(1, '6F', 1, 1), +(2, '3A', 1, 1), +(2, '3B', 1, 1), +(2, '3C', 1, 1), +(2, '3D', 1, 1), +(2, '3E', 1, 1), +(2, '3F', 1, 1), +(2, '4A', 1, 1), +(2, '4B', 1, 1), +(2, '4C', 1, 1), +(2, '4D', 1, 1), +(2, '4E', 1, 1), +(2, '4F', 1, 1), +(2, '5A', 1, 1), +(2, '5B', 1, 1), +(2, '5C', 1, 1), +(2, '5D', 1, 1), +(2, '5E', 1, 1), +(2, '5F', 1, 1), +(2, '6A', 1, 1), +(2, '6B', 1, 1), +(2, '6C', 1, 1), +(2, '6D', 1, 1), +(2, '6E', 1, 1), +(2, '6F', 1, 1); + + + diff --git a/FlightMicroservice/Controllers/FlightController.cs b/FlightMicroservice/Controllers/FlightController.cs index 5ab973f..0e2803d 100644 --- a/FlightMicroservice/Controllers/FlightController.cs +++ b/FlightMicroservice/Controllers/FlightController.cs @@ -56,7 +56,7 @@ namespace FlightMicroservice.Controllers } [HttpGet("{flightId}/capacity")] - public ActionResult GetFlightCapacity([FromRoute] int flightId, [FromQuery] ClassType classType) + public ActionResult GetFlightCapacity([FromRoute] int flightId, [FromQuery] ClassType classType = ClassType.BUSINESS) { Flight? flight = flightService.GetFlight(flightId); if (flight == null) diff --git a/GatewayAPI/Program.cs b/GatewayAPI/Program.cs index 0ed1620..219afdc 100644 --- a/GatewayAPI/Program.cs +++ b/GatewayAPI/Program.cs @@ -9,17 +9,8 @@ builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); -// Add CORS service -builder.Services.AddCors(options => -{ - options.AddPolicy("AllowAirlineClient", builder => - { - builder.WithOrigins("http://localhost:4200") - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials(); - }); -}); +// Add CORS Policy +builder.Services.AddCorsPolicy(builder.Configuration); // Add Http Typed Clients for each Microservice builder.Services.AddHttpClients(builder.Configuration); diff --git a/GatewayAPI/ServiceCollectionExtensions.cs b/GatewayAPI/ServiceCollectionExtensions.cs index 25d509a..a0b0c41 100644 --- a/GatewayAPI/ServiceCollectionExtensions.cs +++ b/GatewayAPI/ServiceCollectionExtensions.cs @@ -29,5 +29,22 @@ namespace GatewayAPI return services; } + + public static IServiceCollection AddCorsPolicy(this IServiceCollection services, ConfigurationManager configurationManager) + { + string baseUrl = configurationManager["ClientService:BaseUrl"] ?? throw new InvalidOperationException("ClientService BaseUrl is not configured."); + services.AddCors(options => + { + options.AddPolicy("AllowAirlineClient", builder => + { + builder.WithOrigins(baseUrl) + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials(); + }); + }); + + return services; + } } } diff --git a/GatewayAPI/appsettings.json b/GatewayAPI/appsettings.json index a5a7960..ef8baaf 100644 --- a/GatewayAPI/appsettings.json +++ b/GatewayAPI/appsettings.json @@ -14,5 +14,8 @@ }, "BookingMicroservice": { "BaseUrl": "http://localhost:5207" + }, + "ClientService": { + "BaseUrl": "http://localhost:4200" } } diff --git a/client/src/components/CustomerBookings/CustomerBookings.tsx b/client/src/components/CustomerBookings/CustomerBookings.tsx index 62078c2..b7116ce 100644 --- a/client/src/components/CustomerBookings/CustomerBookings.tsx +++ b/client/src/components/CustomerBookings/CustomerBookings.tsx @@ -13,7 +13,7 @@ const CustomerBookings = () => { return ( <div className="page-view"> <div className="customer-booking-view"> - <h3>List of {flightType} bookings</h3> + <h3>List of bookings</h3> {bookings.map((booking) => ( <CustomerBookingCard flightId={booking.flightId} diff --git a/client/src/components/FlightCreationForm/FlightCreationForm.tsx b/client/src/components/FlightCreationForm/FlightCreationForm.tsx index faf4543..11c3234 100644 --- a/client/src/components/FlightCreationForm/FlightCreationForm.tsx +++ b/client/src/components/FlightCreationForm/FlightCreationForm.tsx @@ -49,6 +49,16 @@ function FlightCreationForm() { return; } + const today = new Date(); + today.setHours(0, 0, 0, 0); // Reset time to midnight for an accurate date-only comparison + const departureDate = new Date(formValue.departure); + departureDate.setHours(0, 0, 0, 0); // Ensure time components do not affect comparison + + if (departureDate <= today) { + setError('Departure date must be at least for tomorrow.'); + return; + } + setError(''); setDisabled(true); diff --git a/client/src/components/Header/Header.tsx b/client/src/components/Header/Header.tsx index 377f39e..e5efbdb 100644 --- a/client/src/components/Header/Header.tsx +++ b/client/src/components/Header/Header.tsx @@ -26,7 +26,7 @@ function Header() { {isAuth ? <div> <NavLink to={userToDashboard(user)} className={activeClass} >Dashboard</NavLink> - {user?.type === 0 && <NavLink to={'customer/bookings'} className={activeClass}>Upcoming Bookings</NavLink>} + {user?.type === 0 && <NavLink to={'customer/bookings'} className={activeClass}>Bookings List</NavLink>} {user?.type === 0 && <NavLink to={'booking/query'} className={activeClass}>Book a Flight</NavLink>} {user?.type === 1 && <NavLink to={`flights?id=${user.id}`} className={activeClass}>Flight List</NavLink>} <NavLink to={'logout'} className={activeClass}>Logout</NavLink> diff --git a/client/src/components/PaymentForm/PaymentForm.tsx b/client/src/components/PaymentForm/PaymentForm.tsx index c70666a..2426579 100644 --- a/client/src/components/PaymentForm/PaymentForm.tsx +++ b/client/src/components/PaymentForm/PaymentForm.tsx @@ -77,7 +77,7 @@ const PaymentForm = () => { } } catch (error) { console.error('Payment confirmation failed:', error); - setMessage("An error occurred while confirming the payment. Error: ${error.message}"); + setMessage(`An error occurred while confirming the payment.`); } finally { setLoading(false); } diff --git a/client/src/services/BookingView/BookingView.ts b/client/src/services/BookingView/BookingView.ts index 509ede0..c11be3e 100644 --- a/client/src/services/BookingView/BookingView.ts +++ b/client/src/services/BookingView/BookingView.ts @@ -31,19 +31,17 @@ export async function GetBookingInformation({ params: Params; }): Promise<IFullBookingInfo> { const url = `Booking/${params.id}`; - try { - const bookingCall = Api.get(`${url}`, { withCredentials: true }); - const seatsCall = Api.get(`Flight/${params.id}/seats`, { withCredentials: true }); - - const [booking, seats] = await Promise.all([bookingCall, seatsCall]); - return { - booking: booking.data, - seats: seats.data - }; - } catch (error) { - throw error; - } + const bookingResponse = await Api.get(url, { withCredentials: true }); + const flightId = bookingResponse.data.flightId; + + const seatsResponse = await Api.get(`Flight/${flightId}/seats`, { withCredentials: true }); + + return { + booking: bookingResponse.data, + seats: seatsResponse.data + }; + } export async function GetBookingFlight( diff --git a/client/src/services/CustomerBookings/CustomerBookings.ts b/client/src/services/CustomerBookings/CustomerBookings.ts index c01b71f..e10fdfb 100644 --- a/client/src/services/CustomerBookings/CustomerBookings.ts +++ b/client/src/services/CustomerBookings/CustomerBookings.ts @@ -1,4 +1,5 @@ import Api from "../../helpers/Api"; +import UserStorage from "../../helpers/UserStorage"; import { IFlight, ISeat } from "../Dashboard/CustomerDashboard"; export interface IBookingInfo { @@ -17,10 +18,12 @@ export interface IBookingData { export async function GetAllBookings(): Promise<IBookingInfo[]> { const url = `Booking`; try { - const booking = await Api.get(`${url}`, { withCredentials: true }); + const id = UserStorage.getUserId(); + const booking = await Api.get(`${url}?userId=${id}`, { withCredentials: true }); return booking.data as IBookingInfo[]; } catch (error) { throw error; } } + diff --git a/docker-compose.yml b/docker-compose.yml index 1826cc1..bcaa8a5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -55,6 +55,7 @@ services: - UserMicroservice__BaseUrl=http://usermicroservice:8080 - FlightMicroservice__BaseUrl=http://flightmicroservice:8080 - BookingMicroservice__BaseUrl=http://bookingmicroservice:8080 + - ClientService__BaseUrl=http://localhost:${CLIENT_PORT} client: build: -- GitLab