Skip to content
Snippets Groups Projects
Commit dfb49f2b authored by Abdelsamad, Mouaz R (UG - SISC)'s avatar Abdelsamad, Mouaz R (UG - SISC)
Browse files

improvements

parent 49d30a80
No related branches found
No related tags found
No related merge requests found
......@@ -4,10 +4,16 @@ MYSQL_IMAGE_TAG=8.0
# Database configuration
DB_PORT=3307
DB_NAME=myDB
DB_USER=user
DB_PASSWORD=user
#DB_PORT=3307
#DB_NAME=myDB
#DB_USER=user
#DB_PASSWORD=user
#DB_CHARSET=utf8mb4
DB_PORT=3308
DB_NAME=AspNetCoreDb
DB_USER=root
DB_PASSWORD=
DB_CHARSET=utf8mb4
# Service ports
......
using BookingMicroservice.Exceptions;
using BookingMicroservice.Models;
using BookingMicroservice.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
......@@ -19,6 +20,7 @@ namespace BookingMicroservice.Controllers
this.bookingService = bookingService;
}
[Authorize]
[HttpGet()]
public IActionResult GetBookings(int? flightId = null, int? userId = null, BookingClass? bookingClass = null)
{
......@@ -29,6 +31,7 @@ namespace BookingMicroservice.Controllers
return Ok(bookings);
}
[Authorize]
[HttpGet("{id}")]
public IActionResult GetBooking([FromRoute] int id)
{
......@@ -39,6 +42,7 @@ namespace BookingMicroservice.Controllers
return Ok(booking);
}
[Authorize]
[HttpPost()]
public async Task<IActionResult> MakeBooking([FromBody] BookingCreation bookingCreationModel)
{
......@@ -47,20 +51,32 @@ namespace BookingMicroservice.Controllers
if (!int.TryParse(userIdValue, out int userId))
return BadRequest("Unable to get User Id from Token");
Booking booking = await reservationComplianceService.TryCreateBookingAsync(bookingCreationModel.FlightId, userId, bookingCreationModel.BookingClass, bookingCreationModel.SeatId);
if (booking == null)
return BadRequest("Error in creating booking");
try
{
Booking? booking = await reservationComplianceService.TryCreateBookingAsync(bookingCreationModel.FlightId, userId, bookingCreationModel.BookingClass, bookingCreationModel.SeatId);
if (booking == null)
return BadRequest("Error in creating booking");
return Ok(booking);
return Ok(booking);
}
catch (InvalidOperationException exception)
{
return BadRequest(exception.Message);
}
catch (BookingException exception)
{
return BadRequest(exception.Message);
}
}
[Authorize]
[HttpPut("{bookingId}")]
public async Task<IActionResult> UpdatedBookingSeat([FromRoute] int bookingId, [FromBody] BookingUpdate bookingUpdateModel)
{
try
{
await reservationComplianceService.TryBookSeatAsync(bookingId, bookingUpdateModel.SeatId);
return Ok();
return Ok(new { BookedSeat = true, Message = "Seat booked successfully." });
}
catch (InvalidOperationException exception)
{
......@@ -68,7 +84,7 @@ namespace BookingMicroservice.Controllers
}
catch (BookingException exception)
{
return BadRequest(exception.Message);
return Ok(new { BookedSeat = false, Message = exception.Message });
}
}
}
......
using System.Net;
namespace BookingMicroservice.Handlers
{
public class RequestCookieHandler : DelegatingHandler
{
private readonly IHttpContextAccessor httpContextAccessor;
public RequestCookieHandler(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpContext? context = httpContextAccessor.HttpContext;
if (context?.Request.Cookies != null && request.RequestUri != null)
{
CookieContainer cookieContainer = new CookieContainer();
foreach (KeyValuePair<string, string> cookie in context.Request.Cookies)
{
if (!string.IsNullOrEmpty(cookie.Value) && (cookie.Key == "AccessToken" || cookie.Key == "RefreshToken"))
cookieContainer.Add(request.RequestUri, new Cookie(cookie.Key, cookie.Value));
}
var cookieHeader = cookieContainer.GetCookieHeader(request.RequestUri);
if (!string.IsNullOrEmpty(cookieHeader))
request.Headers.Add("Cookie", cookieHeader);
}
return await base.SendAsync(request, cancellationToken);
}
}
}
......@@ -9,6 +9,8 @@ using System.Text;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpContextAccessor();
builder.Services.AddTransient<RequestCookieHandler>();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
......@@ -29,14 +31,31 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
ValidIssuer = builder.Configuration["Jwt:Issuer"] ?? throw new InvalidOperationException("JWT Issuer is not configured."),
ValidAudience = builder.Configuration["Jwt:Audience"] ?? throw new InvalidOperationException("JWT Audience is not configured.")
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Console.WriteLine("Authentication failed: " + context.Exception.Message);
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
Console.WriteLine("Token validated");
return Task.CompletedTask;
}
};
});
builder.Services.AddHttpClient<IFlightServiceClient, FlightServiceClient>(client =>
{
string baseURL = builder.Configuration["FlightMicroservice:BaseUrl"] ?? throw new InvalidOperationException("FlightMicroservice BaseUrl is not configured.");
string? baseURL = builder.Configuration["FlightMicroservice:BaseUrl"];
if (string.IsNullOrEmpty(baseURL))
throw new InvalidOperationException("FlightMicroservice BaseUrl is not configured.");
baseURL = baseURL.EndsWith("/") ? baseURL : baseURL + "/";
client.BaseAddress = new Uri(baseURL);
});
}).AddHttpMessageHandler<RequestCookieHandler>(); ;
builder.Services.AddScoped<IBookingService, BookingService>();
builder.Services.AddScoped<IReservationComplianceService, ReservationComplianceService>();
......@@ -64,7 +83,8 @@ app.Use(async (context, next) =>
await next();
});
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
......@@ -30,9 +30,9 @@ namespace BookingMicroservice.Services
return bookings;
}
public Booking CreateBooking(int flightId, int userId, BookingClass bookingClass, int? seatId)
public Booking CreateBooking(int flightId, int userId, BookingClass bookingClass)
{
Booking booking = new Booking(flightId, userId, bookingClass, seatId);
Booking booking = new Booking(flightId, userId, bookingClass, null);
dbContext.Bookings.Add(booking);
dbContext.SaveChanges();
......
......@@ -4,7 +4,7 @@ namespace BookingMicroservice.Services
{
public interface IBookingService
{
Booking CreateBooking(int flightId, int userId, BookingClass bookingClass, int? seatId);
Booking CreateBooking(int flightId, int userId, BookingClass bookingClass);
List<Booking> GetBookings(int? flightId = null, int? userId = null, BookingClass? bookingClass = null);
Booking? GetBooking(int bookingId);
void DeleteBooking(int bookingId);
......
......@@ -4,7 +4,7 @@ namespace BookingMicroservice.Services
{
public interface IReservationComplianceService
{
Task<Booking> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId);
Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId);
Task TryBookSeatAsync(int bookingId, int seatId);
}
......
......@@ -10,7 +10,7 @@ namespace BookingMicroservice.Services
private readonly IFlightServiceClient flightServiceClient;
private const string NO_AVAILABLE_SEAT_MSG = "Unfortunately, there are no {0} seats available for this flight. Please try selecting a different class, flight, or date.";
private const string BOOKED_SEAT_MSG = "The selected seat is already booked. Please choose a different seat";
private const string BOOKED_SEAT_MSG = "The selected seat is already booked. Please choose a different seat.";
public ReservationComplianceService(IBookingService bookingService, IFlightServiceClient flightServiceClient)
{
......@@ -18,7 +18,7 @@ namespace BookingMicroservice.Services
this.flightServiceClient = flightServiceClient;
}
public async Task<Booking> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId)
public async Task<Booking?> TryCreateBookingAsync(int flightId, int userId, BookingClass bookingClass, int? seatId)
{
HttpResponseMessage capacityResponse = await flightServiceClient.GetFlightCapacityAsync(flightId, (int)bookingClass);
if (!capacityResponse.IsSuccessStatusCode)
......@@ -29,13 +29,28 @@ namespace BookingMicroservice.Services
throw new InvalidOperationException("Invalid capacity value received from flight service.");
// Get current bookings for the flight and class
//int currentBookings = bookingService.GetBookingForFlight(flightId).Count(booking => booking.BookingClass == bookingClass);
int currentBookings = bookingService.GetBookings(flightId: flightId, bookingClass: bookingClass).Count();
if (currentBookings >= capacity)
throw new BookingException(string.Format(NO_AVAILABLE_SEAT_MSG, bookingClass.ToString().ToLower()));
return bookingService.CreateBooking(flightId, userId, bookingClass, seatId);
Booking booking = bookingService.CreateBooking(flightId, userId, bookingClass);
if(seatId.HasValue && booking?.Id != null)
{
try
{
await TryBookSeatAsync(booking.Id, seatId.Value);
booking.SetSeatNumber(seatId.Value);
}
catch (Exception exception)
{
// delete booking as there has been a failure in booking the seat
bookingService.DeleteBooking(booking.Id);
throw new InvalidOperationException($@"Booking has been cancelled as there has been an issue with selecting the seat.{Environment.NewLine}{exception.Message}{Environment.NewLine}Please try again.");
}
}
return booking;
}
public async Task TryBookSeatAsync(int bookingId, int seatId)
......@@ -52,10 +67,11 @@ namespace BookingMicroservice.Services
throw new BookingException(BOOKED_SEAT_MSG);
HttpResponseMessage seatBookingRespone = await flightServiceClient.BookSeatAsync(seatId);
string capacityString = await seatBookingRespone.Content.ReadAsStringAsync(); // remove this later
if (!seatAvailabilityResponse.IsSuccessStatusCode)
throw new InvalidOperationException("Error booking seat.");
if (!seatBookingRespone.IsSuccessStatusCode) {
string? failureMessage = seatBookingRespone.ReasonPhrase;
throw new InvalidOperationException($"Error booking seat; {failureMessage}");
}
bookingService.UpdateBooking(bookingId, seatId);
}
......
......@@ -64,7 +64,7 @@ namespace FlightMicroservice.Controllers
int seatCapacity = classType == ClassType.BUSINESS ? flight.BusinessCapacity : flight.EconomyCapacity;
return Ok(new { ClassType = classType.ToString(), Capacity = seatCapacity });
return Ok(seatCapacity);
}
......
......@@ -58,7 +58,7 @@ namespace FlightMicroservice.Controllers
try
{
bool isAvailable = seatService.IsAvailable(id);
return Ok(new { IsAvailable = isAvailable });
return Ok(isAvailable);
}
catch (KeyNotFoundException ex)
{
......
......@@ -47,16 +47,16 @@ services:
ports:
- "${CLIENT_PORT}:4200"
db:
image: mysql:${MYSQL_IMAGE_TAG}
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
MYSQL_USER: ${DB_USER}
MYSQL_PASSWORD: ${DB_PASSWORD}
volumes:
- ./Database:/docker-entrypoint-initdb.d
ports:
- "${DB_PORT}:3306"
# db:
# image: mysql:${MYSQL_IMAGE_TAG}
# command: --default-authentication-plugin=mysql_native_password
# restart: always
# environment:
# MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
# MYSQL_DATABASE: ${DB_NAME}
# MYSQL_USER: ${DB_USER}
# MYSQL_PASSWORD: ${DB_PASSWORD}
# volumes:
# - ./Database:/docker-entrypoint-initdb.d
# ports:
# - "${DB_PORT}:3306"
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment