From 5cf8cdcae887da56e2db67f45215c33a8737d969 Mon Sep 17 00:00:00 2001
From: Mouaz Abdelsamad <ma03081@surrey.ac.uk>
Date: Sat, 6 Apr 2024 23:16:20 +0100
Subject: [PATCH] improvemenets

---
 Database/InitTables.sql                       |  5 ++-
 .../Controllers/FlightController.cs           | 19 ++++++++-
 FlightMicroservice/FlightMicroservice.csproj  |  2 +-
 .../Handler/ExceptionHandler.cs               | 40 ++++++++++++++++++
 FlightMicroservice/Models/Flight.cs           |  5 ++-
 FlightMicroservice/Program.cs                 |  2 +
 FlightMicroservice/Services/FlightService.cs  | 11 ++++-
 FlightMicroservice/Services/IFlightService.cs |  3 +-
 .../FlightService/FlightServiceClient.cs      |  6 +++
 .../FlightService/IFlightServiceClient.cs     |  1 +
 GatewayAPI/Controllers/FlightController.cs    |  8 ++++
 UserMicroservice/Handlers/ExceptionHandler.cs | 41 +++++++++++++++++++
 UserMicroservice/Program.cs                   |  2 +
 13 files changed, 137 insertions(+), 8 deletions(-)
 create mode 100644 FlightMicroservice/Handler/ExceptionHandler.cs
 create mode 100644 UserMicroservice/Handlers/ExceptionHandler.cs

diff --git a/Database/InitTables.sql b/Database/InitTables.sql
index 6805d23..dd06e9e 100644
--- a/Database/InitTables.sql
+++ b/Database/InitTables.sql
@@ -15,14 +15,15 @@ CREATE TABLE RefreshTokens (
 
 CREATE TABLE Flights (
     Id INT AUTO_INCREMENT PRIMARY KEY,
+    AirlineId INT NOT NULL,
     Origin LONGTEXT NOT NULL,
     Destination LONGTEXT NOT NULL,
     DepartureTime DATETIME(6) NOT NULL,
     ArrivalTime DATETIME(6) NOT NULL,
     EconomyCapacity INT NOT NULL,
     BusinessCapacity INT NOT NULL,
-    EconomyPrice DECIMAL(65, 30) NOT NULL,
-    BusinessPrice DECIMAL(65, 30) NOT NULL
+    EconomyPrice DECIMAL(19, 2) NOT NULL,
+    BusinessPrice DECIMAL(19, 2) NOT NULL
 );
 
 CREATE TABLE Seats (
diff --git a/FlightMicroservice/Controllers/FlightController.cs b/FlightMicroservice/Controllers/FlightController.cs
index 4e1dc43..ea3411b 100644
--- a/FlightMicroservice/Controllers/FlightController.cs
+++ b/FlightMicroservice/Controllers/FlightController.cs
@@ -2,6 +2,7 @@
 using FlightMicroservice.Services;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
+using System.Security.Claims;
 
 namespace FlightMicroservice.Controllers
 {
@@ -40,8 +41,12 @@ namespace FlightMicroservice.Controllers
         [HttpPost()]
         public ActionResult AddFlight([FromBody] FlightCreationModel model)
         {
+            string? airlineIdValue = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
+            if (!int.TryParse(airlineIdValue, out int airlineId))
+                return BadRequest("Unable to get Airline Id from Token");
+
             Flight flight = flightService.CreateFlight(
-                model.Origin, model.Destination, model.DepartureTime, model.ArrivalTime,
+                airlineId, model.Origin, model.Destination, model.DepartureTime, model.ArrivalTime,
                 model.EconomyCapacity, model.BusinessCapacity, model.EconomyPrice, model.BusinessPrice);
 
             if (flight == null)
@@ -50,7 +55,6 @@ namespace FlightMicroservice.Controllers
             return Ok(flight);
         }
 
-        [Authorize]
         [HttpGet("{flightId}/capacity")]
         public ActionResult GetFlightCapacity([FromRoute] int flightId, [FromQuery] ClassType classType)
         {
@@ -64,5 +68,16 @@ namespace FlightMicroservice.Controllers
         }
 
 
+        [HttpGet("{flightId}/seats")]
+        public IActionResult GetFlightSeats([FromRoute] int flightId)
+        {
+            List<Seat>? seats = flightService.GetSeatsByFlightId(flightId);
+            if (seats == null)
+                return NotFound($"Flight with Id {flightId} does not exist or could not be found.");
+
+            return Ok(seats);
+        }
+
+
     }
 }
diff --git a/FlightMicroservice/FlightMicroservice.csproj b/FlightMicroservice/FlightMicroservice.csproj
index 8b66623..ba9f074 100644
--- a/FlightMicroservice/FlightMicroservice.csproj
+++ b/FlightMicroservice/FlightMicroservice.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
+<Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
     <TargetFramework>net8.0</TargetFramework>
diff --git a/FlightMicroservice/Handler/ExceptionHandler.cs b/FlightMicroservice/Handler/ExceptionHandler.cs
new file mode 100644
index 0000000..ef916a7
--- /dev/null
+++ b/FlightMicroservice/Handler/ExceptionHandler.cs
@@ -0,0 +1,40 @@
+using System.Net;
+using System.Text.Json;
+
+namespace FlightMicroservice.Handler
+{
+    public class ExceptionHandler
+    {
+        private readonly RequestDelegate next;
+
+        public ExceptionHandler(RequestDelegate next)
+        {
+            this.next = next;
+        }
+
+        public async Task Invoke(HttpContext context)
+        {
+            try
+            {
+                await next(context);
+            }
+            catch (Exception ex)
+            {
+                if (!context.Response.HasStarted)
+                {
+                    var response = context.Response;
+                    response.ContentType = "application/json";
+                    response.StatusCode = (int)HttpStatusCode.InternalServerError;
+
+                    var result = JsonSerializer.Serialize(new
+                    {
+                        response.StatusCode,
+                        ex.Message
+                    });
+
+                    await response.WriteAsync(result);
+                }
+            }
+        }
+    }
+}
diff --git a/FlightMicroservice/Models/Flight.cs b/FlightMicroservice/Models/Flight.cs
index 257bdef..73a66ac 100644
--- a/FlightMicroservice/Models/Flight.cs
+++ b/FlightMicroservice/Models/Flight.cs
@@ -6,6 +6,7 @@
         internal static readonly int ECONOMY_SEATS_PER_ROW = 6;
 
         public int Id { get; private set; }
+        public int AirlineId { get; internal set; }
         public string Origin { get; internal set; }
         public string Destination { get; internal set; }
         public DateTime DepartureTime { get; internal set; }
@@ -18,7 +19,8 @@
 
         public Flight() => Seats = new List<Seat>();
 
-        public Flight(string origin, 
+        public Flight(int airlineId,
+                      string origin, 
                       string destination,  
                       DateTime departureTime, 
                       DateTime arrivalTime,
@@ -34,6 +36,7 @@
             if (!IsCapacityValid(businessCapacity, BUSINESS_SEATS_PER_ROW))
                 throw new ArgumentException($"Capacity of Business seats must be a multiple of {BUSINESS_SEATS_PER_ROW}");
 
+            AirlineId = airlineId;
             Origin = origin;
             Destination = destination;
             DepartureTime = departureTime;
diff --git a/FlightMicroservice/Program.cs b/FlightMicroservice/Program.cs
index 82fabff..151b9c8 100644
--- a/FlightMicroservice/Program.cs
+++ b/FlightMicroservice/Program.cs
@@ -1,3 +1,4 @@
+using FlightMicroservice.Handler;
 using FlightMicroservice.Models;
 using FlightMicroservice.Services;
 using Microsoft.AspNetCore.Authentication.JwtBearer;
@@ -47,6 +48,7 @@ if (app.Environment.IsDevelopment())
     app.UseSwaggerUI();
 }
 
+app.UseMiddleware<ExceptionHandler>();
 app.UseHttpsRedirection();
 
 // Middleware for handling the access token in cookies
diff --git a/FlightMicroservice/Services/FlightService.cs b/FlightMicroservice/Services/FlightService.cs
index aa905a1..91e30b8 100644
--- a/FlightMicroservice/Services/FlightService.cs
+++ b/FlightMicroservice/Services/FlightService.cs
@@ -1,4 +1,5 @@
 using FlightMicroservice.Models;
+using Microsoft.EntityFrameworkCore;
 
 namespace FlightMicroservice.Services
 {
@@ -37,6 +38,7 @@ namespace FlightMicroservice.Services
         }
 
         public Flight CreateFlight(
+            int airlineId,
             string origin, 
             string destination, 
             DateTime departureTime, 
@@ -46,7 +48,7 @@ namespace FlightMicroservice.Services
             decimal economyPrice, 
             decimal businessPrice)
         {
-            Flight flight = new Flight(origin, destination, departureTime, arrivalTime, economyCapacity, businessCapacity, economyPrice, businessPrice);
+            Flight flight = new Flight(airlineId, origin, destination, departureTime, arrivalTime, economyCapacity, businessCapacity, economyPrice, businessPrice);
 
             InitializeSeatsForFlight(flight);
 
@@ -68,6 +70,13 @@ namespace FlightMicroservice.Services
             return true;
         }
 
+        public List<Seat> GetSeatsByFlightId(int flightId)
+        {
+            return dbContext.Seats
+                .Where(seat => seat.FlightId == flightId) 
+                .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 c9e9a03..f3bed26 100644
--- a/FlightMicroservice/Services/IFlightService.cs
+++ b/FlightMicroservice/Services/IFlightService.cs
@@ -6,7 +6,8 @@ namespace FlightMicroservice.Services
     {
         Flight? GetFlight(int flightId);
         List<Flight> GetFlights(string? origin, string? destination, DateTime? departureTime, DateTime? arrivalTime);
-        Flight CreateFlight(string origin, string destination, DateTime departureTime, DateTime arrivalTime, int economyCapacity, int businessCapacity, decimal economyPrice, decimal businessPrice);
+        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);
     }
 }
diff --git a/GatewayAPI/Clients/FlightService/FlightServiceClient.cs b/GatewayAPI/Clients/FlightService/FlightServiceClient.cs
index cdf5f3a..82e4ca7 100644
--- a/GatewayAPI/Clients/FlightService/FlightServiceClient.cs
+++ b/GatewayAPI/Clients/FlightService/FlightServiceClient.cs
@@ -49,6 +49,12 @@ namespace GatewayAPI.Clients.FlightService
             return await httpClient.GetAsync($"{FLIGHT_API_PATH}/{flightId}/capacity?ClassType={classType}");
         }
 
+        public async Task<HttpResponseMessage> GetFlightSeatsAsync(int flightId)
+        {
+            return await httpClient.GetAsync($"{FLIGHT_API_PATH}/{flightId}/seats");
+        }
+
+
 
 
 
diff --git a/GatewayAPI/Clients/FlightService/IFlightServiceClient.cs b/GatewayAPI/Clients/FlightService/IFlightServiceClient.cs
index def17a9..ac86b80 100644
--- a/GatewayAPI/Clients/FlightService/IFlightServiceClient.cs
+++ b/GatewayAPI/Clients/FlightService/IFlightServiceClient.cs
@@ -8,6 +8,7 @@ namespace GatewayAPI.Clients.FlightService
         Task<HttpResponseMessage> GetFlightsAsync(string? origin = null, string? destination = null, DateTime? departureTime = null, DateTime? arrivalTime = null);
         Task<HttpResponseMessage> AddFlightAsync(FlightCreation flight);
         Task<HttpResponseMessage> GetFlightCapacityAsync(int flightId, int classType);
+        Task<HttpResponseMessage> GetFlightSeatsAsync(int flightId);
 
 
         Task<HttpResponseMessage> GetSeatsAsync();
diff --git a/GatewayAPI/Controllers/FlightController.cs b/GatewayAPI/Controllers/FlightController.cs
index e335bd1..c567683 100644
--- a/GatewayAPI/Controllers/FlightController.cs
+++ b/GatewayAPI/Controllers/FlightController.cs
@@ -43,5 +43,13 @@ namespace GatewayAPI.Controllers
             HttpResponseMessage response = await flightServiceClient.GetFlightCapacityAsync(id, classType);
             return new HttpResponseMessageResult(response);
         }
+
+        [HttpGet("{id}/seats")]
+        public async Task<IActionResult> GetFlightSeats([FromRoute] int id)
+        {
+            HttpResponseMessage response = await flightServiceClient.GetFlightSeatsAsync(id);
+            return new HttpResponseMessageResult(response);
+        }
+
     }
 }
diff --git a/UserMicroservice/Handlers/ExceptionHandler.cs b/UserMicroservice/Handlers/ExceptionHandler.cs
new file mode 100644
index 0000000..fec7e76
--- /dev/null
+++ b/UserMicroservice/Handlers/ExceptionHandler.cs
@@ -0,0 +1,41 @@
+using System.Net;
+using System.Text.Json;
+
+namespace UserMicroservice.Handlers
+{
+    public class ExceptionHandler
+    {
+        private readonly RequestDelegate next;
+
+        public ExceptionHandler(RequestDelegate next)
+        {
+            this.next = next;
+        }
+
+        public async Task Invoke(HttpContext context)
+        {
+            try
+            {
+                await next(context);
+            }
+            catch (Exception ex)
+            {
+                if (!context.Response.HasStarted)
+                {
+                    var response = context.Response;
+                    response.ContentType = "application/json";
+                    response.StatusCode = (int)HttpStatusCode.InternalServerError;
+
+                    var result = JsonSerializer.Serialize(new
+                    {
+                        response.StatusCode,
+                        ex.Message
+                    });
+
+                    await response.WriteAsync(result);
+                }
+            }
+        }
+
+    }
+}
diff --git a/UserMicroservice/Program.cs b/UserMicroservice/Program.cs
index cbfa241..f42cffd 100644
--- a/UserMicroservice/Program.cs
+++ b/UserMicroservice/Program.cs
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.IdentityModel.Tokens;
 using System.Text;
 using Microsoft.AspNetCore.Identity;
+using UserMicroservice.Handlers;
 
 var builder = WebApplication.CreateBuilder(args);
 
@@ -46,6 +47,7 @@ if (app.Environment.IsDevelopment())
     app.UseSwaggerUI();
 }
 
+app.UseMiddleware<ExceptionHandler>();
 app.UseHttpsRedirection();
 
 // Middleware to check for the access token in cookies
-- 
GitLab