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

Added Flight Service

parent 3742927f
No related branches found
No related tags found
No related merge requests found
Showing
with 686 additions and 0 deletions
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
\ No newline at end of file
using FlightMicroservice.Models;
using FlightMicroservice.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace FlightMicroservice.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class FlightController : ControllerBase
{
private readonly IFlightService flightService;
public FlightController(IFlightService flightService)
{
this.flightService = flightService;
}
[HttpGet()]
public ActionResult GetFlights(string? origin = null, string? destination = null, DateTime? departureTime = null, DateTime? arrivalTime = null)
{
List<Flight> flights = flightService.GetFlights(origin, destination, departureTime, arrivalTime);
if (flights == null)
return BadRequest();
return Ok(flights);
}
[HttpGet("{id}")]
public ActionResult GetFlight(int id)
{
Flight? flight = flightService.GetFlight(id);
if (flight == null)
return NotFound($"Could Not Find a Flight with Id: {id}");
return Ok(flight);
}
[Authorize]
[HttpPost()]
public ActionResult AddFlight([FromBody] FlightCreationModel model)
{
Flight flight = flightService.CreateFlight(
model.Origin, model.Destination, model.DepartureTime, model.ArrivalTime,
model.EconomyCapacity, model.BusinessCapacity, model.EconomyPrice, model.BusinessPrice);
if (flight == null)
return BadRequest("Failed to create the flight.");
return Ok(flight);
}
[Authorize]
[HttpGet("{flightId}/capacity")]
public ActionResult GetFlightCapacity([FromRoute] int flightId, [FromQuery] ClassType classType)
{
Flight? flight = flightService.GetFlight(flightId);
if (flight == null)
return NotFound($"Could Not Find a Flight with Id: {flightId}");
int seatCapacity = classType == ClassType.BUSINESS ? flight.BusinessCapacity : flight.EconomyCapacity;
return Ok(new { ClassType = classType.ToString(), Capacity = seatCapacity });
}
}
}
using FlightMicroservice.Models;
using FlightMicroservice.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace FlightMicroservice.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class SeatController : ControllerBase
{
private readonly ISeatService seatService;
public SeatController(ISeatService seatService)
{
this.seatService = seatService;
}
[HttpGet]
public ActionResult GetSeats()
{
List<Seat> seats = seatService.GetSeats();
if(seats == null)
return BadRequest();
return Ok(seats);
}
[HttpGet("{id}")]
public ActionResult GetSeat(int id)
{
Seat? seat = seatService.GetSeat(id);
if(seat == null)
return NotFound($"Could Not Find Seat of Id: {id}");
return Ok(seat);
}
[Authorize]
[HttpPut("{id}")]
public ActionResult BookSeat(int id)
{
try
{
seatService.BookSeat(id);
return Ok();
}
catch (KeyNotFoundException ex)
{
return BadRequest(ex.Message);
}
}
[HttpGet("{id}/isAvailable")]
public ActionResult IsAvailable(int id)
{
try
{
bool isAvailable = seatService.IsAvailable(id);
return Ok(new { IsAvailable = isAvailable });
}
catch (KeyNotFoundException ex)
{
return BadRequest(ex.Message);
}
}
}
}
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["FlightMicroservice.csproj", "."]
RUN dotnet restore "./FlightMicroservice.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./FlightMicroservice.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./FlightMicroservice.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "FlightMicroservice.dll"]
\ No newline at end of file
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>78cc9c8d-b053-40f7-a429-a85bbb577e26</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>http</ActiveDebugProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
\ No newline at end of file
@FlightMicroservice_HostAddress = http://localhost:5175
GET {{FlightMicroservice_HostAddress}}/weatherforecast/
Accept: application/json
###

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34622.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlightMicroservice", "FlightMicroservice.csproj", "{E3CFECA9-1502-4C6D-B8AE-227B91C9D77C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E3CFECA9-1502-4C6D-B8AE-227B91C9D77C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E3CFECA9-1502-4C6D-B8AE-227B91C9D77C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3CFECA9-1502-4C6D-B8AE-227B91C9D77C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3CFECA9-1502-4C6D-B8AE-227B91C9D77C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2EF46619-6121-43AA-AA9A-229600A078A6}
EndGlobalSection
EndGlobal
using Microsoft.EntityFrameworkCore;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
namespace FlightMicroservice.Models
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Flight> Flights { get; set; }
public DbSet<Seat> Seats { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Seat>()
.HasOne(seat => seat.Flight)
.WithMany(flight => flight.Seats)
.HasForeignKey(seat => seat.FlightId);
}
}
}
namespace FlightMicroservice.Models
{
public class Flight
{
internal static readonly int BUSINESS_SEATS_PER_ROW = 4;
internal static readonly int ECONOMY_SEATS_PER_ROW = 6;
public int Id { get; private set; }
public string Origin { get; internal set; }
public string Destination { get; internal set; }
public DateTime DepartureTime { get; internal set; }
public DateTime ArrivalTime { get; internal set; }
public int EconomyCapacity { get; internal set; }
public int BusinessCapacity { get; internal set; }
public decimal EconomyPrice { get; internal set; }
public decimal BusinessPrice { get; internal set; }
public ICollection<Seat> Seats { get; internal set; }
public Flight() => Seats = new List<Seat>();
public Flight(string origin,
string destination,
DateTime departureTime,
DateTime arrivalTime,
int economyCapacity,
int businessCapacity,
decimal economyPrice,
decimal businessPrice
)
{
if(!IsCapacityValid(economyCapacity, ECONOMY_SEATS_PER_ROW))
throw new ArgumentException($"Capacity of Economy seats must be a multiple of {ECONOMY_SEATS_PER_ROW}");
if (!IsCapacityValid(businessCapacity, BUSINESS_SEATS_PER_ROW))
throw new ArgumentException($"Capacity of Business seats must be a multiple of {BUSINESS_SEATS_PER_ROW}");
Origin = origin;
Destination = destination;
DepartureTime = departureTime;
ArrivalTime = arrivalTime;
EconomyCapacity = economyCapacity;
BusinessCapacity = businessCapacity;
EconomyPrice = economyPrice;
BusinessPrice = businessPrice;
Seats = new List<Seat>();
}
private bool IsCapacityValid(int numberOfSeats, int multipleOf)
{
return numberOfSeats % multipleOf == 0;
}
}
}
namespace FlightMicroservice.Models
{
public class FlightCreationModel
{
public required string Origin { get; set; }
public required string Destination { get; set; }
public required DateTime DepartureTime { get; set; }
public required DateTime ArrivalTime { get; set; }
public required int EconomyCapacity { get; set; }
public required int BusinessCapacity { get; set; }
public required decimal EconomyPrice { get; set; }
public required decimal BusinessPrice { get; set; }
}
}
namespace FlightMicroservice.Models
{
public class Seat
{
public int Id { get; private set; }
public int FlightId { get; internal set; }
public string SeatNumber { get; internal set; }
public ClassType ClassType { get; internal set; }
public bool IsAvailable { get; internal set; }
public Flight Flight { get; internal set; }
public Seat() { }
public Seat(int flightId, string seatNumber, ClassType classType, bool isAvailable)
{
FlightId = flightId;
SeatNumber = seatNumber;
ClassType = classType;
IsAvailable = isAvailable;
}
}
public enum ClassType
{
BUSINESS = 0,
ECONOMY = 1
}
}
using FlightMicroservice.Models;
using FlightMicroservice.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(builder.Configuration.GetConnectionString("DefaultConnection"),
new MariaDbServerVersion(new Version(10, 4, 20))));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"]
};
});
// Add dependency injections
builder.Services.AddScoped<IFlightService, FlightService>();
builder.Services.AddScoped<ISeatService, SeatService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5175"
},
"https": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7019;http://localhost:5175"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTPS_PORTS": "8081",
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:30200",
"sslPort": 44344
}
}
}
\ No newline at end of file
using FlightMicroservice.Models;
namespace FlightMicroservice.Services
{
public class FlightService : IFlightService
{
private readonly ApplicationDbContext dbContext;
public FlightService(ApplicationDbContext dbContext)
{
this.dbContext = dbContext;
}
public Flight? GetFlight(int flightId)
{
Flight? flight = dbContext.Flights.SingleOrDefault(flight => flight.Id == flightId);
return flight;
}
public List<Flight> GetFlights(string? origin, string? destination, DateTime? departureTime, DateTime? arrivalTime)
{
IQueryable<Flight> query = dbContext.Flights.AsQueryable();
if (!string.IsNullOrWhiteSpace(origin))
query = query.Where(flight => flight.Origin == origin);
if (!string.IsNullOrWhiteSpace(destination))
query = query.Where(flight => flight.Destination == destination);
if (departureTime.HasValue)
query = query.Where(flight => flight.DepartureTime.Date == departureTime.Value.Date);
if (arrivalTime.HasValue)
query = query.Where(flight => flight.ArrivalTime.Date == arrivalTime.Value.Date);
return query.ToList();
}
public Flight CreateFlight(
string origin,
string destination,
DateTime departureTime,
DateTime arrivalTime,
int economyCapacity,
int businessCapacity,
decimal economyPrice,
decimal businessPrice)
{
Flight flight = new Flight(origin, destination, departureTime, arrivalTime, economyCapacity, businessCapacity, economyPrice, businessPrice);
InitializeSeatsForFlight(flight);
dbContext.Flights.Add(flight);
dbContext.SaveChanges();
return flight;
}
public bool RemoveFlight(int flightId)
{
Flight? flight = dbContext.Flights.SingleOrDefault(flight => flight.Id == flightId);
if (flight == null)
return false;
dbContext.Flights.Remove(flight);
dbContext.SaveChanges();
return true;
}
private void InitializeSeatsForFlight(Flight flight)
{
int businessRows = flight.BusinessCapacity / Flight.BUSINESS_SEATS_PER_ROW;
int economyRows = flight.EconomyCapacity / Flight.ECONOMY_SEATS_PER_ROW;
// Initialize Business class seats
for (int row = 1; row <= businessRows; row++)
{
for (char seat = 'A'; seat < 'A' + Flight.BUSINESS_SEATS_PER_ROW; seat++)
{
flight.Seats.Add(new Seat
{
ClassType = ClassType.BUSINESS,
SeatNumber = $"{row}{seat}",
IsAvailable = true
});
}
}
// Initialize Economy class seats
int startingEconomyRow = businessRows + 1; // Economy rows start after the last Business row
for (int row = startingEconomyRow; row < startingEconomyRow + economyRows; row++)
{
for (char seat = 'A'; seat < 'A' + Flight.ECONOMY_SEATS_PER_ROW; seat++)
{
flight.Seats.Add(new Seat
{
ClassType = ClassType.ECONOMY,
SeatNumber = $"{row}{seat}",
IsAvailable = true
});
}
}
}
}
}
using FlightMicroservice.Models;
namespace FlightMicroservice.Services
{
public interface IFlightService
{
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);
bool RemoveFlight(int flightId);
}
}
using FlightMicroservice.Models;
namespace FlightMicroservice.Services
{
public interface ISeatService
{
List<Seat> GetSeats();
Seat? GetSeat(int id);
void BookSeat(int id);
bool IsAvailable(int id);
}
}
using FlightMicroservice.Models;
using Microsoft.EntityFrameworkCore;
namespace FlightMicroservice.Services
{
public class SeatService : ISeatService
{
private readonly ApplicationDbContext dbContext;
public SeatService(ApplicationDbContext dbContext)
{
this.dbContext = dbContext;
}
public List<Seat> GetSeats()
{
List<Seat> seats = dbContext.Seats.ToList();
return seats;
}
public Seat? GetSeat(int id)
{
Seat? seat = dbContext.Seats.FirstOrDefault(seat => seat.Id == id);
return seat;
}
public void BookSeat(int id)
{
int affectedRows = dbContext.Seats
.Where(seat => seat.Id == id)
.ExecuteUpdate(setters => setters
.SetProperty(seat => seat.IsAvailable, true));
dbContext.SaveChanges();
if (affectedRows == 0)
throw new KeyNotFoundException($"A seat with the ID {id} was not found.");
}
public bool IsAvailable(int id)
{
Seat? seat = dbContext.Seats.FirstOrDefault(seat => seat.Id == id);
if(seat == null)
throw new KeyNotFoundException($"A seat with the ID {id} was not found.");
return seat.IsAvailable;
}
}
}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "server=localhost;port=3308;database=AspNetCoreDb;user=root;password=;CharSet=utf8mb4;"
},
"Jwt": {
"Key": "0QTrd3jToEYj205k01A2R87Hc5YpqDNeywg7JzQpczs=",
"Issuer": "http://localhost:5175",
"Audience": "http://localhost:5175"
}
}
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