372 lines
10 KiB
TypeScript
372 lines
10 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Get,
|
|
Delete,
|
|
Patch,
|
|
Post,
|
|
Query,
|
|
HttpException,
|
|
HttpStatus,
|
|
} from '@nestjs/common';
|
|
import { ApiBody, ApiQuery, ApiResponse } from '@nestjs/swagger';
|
|
import { AirportService } from './airport.service';
|
|
import { Airport } from './models/airport.model';
|
|
import { AirportDto } from './dto/airport.dto';
|
|
import { ArrivalRouteDto } from './dto/arrivalroute.dto';
|
|
import { AssignmentDto } from './dto/assignment.dto';
|
|
import { ConstraintDto } from './dto/constraint.dto';
|
|
import { PlanningDto } from './dto/planning.dto';
|
|
import { RunwaySpacingDto } from './dto/runwayspacing.dto';
|
|
import { ArrivalRoute } from './models/arrivalroute.model';
|
|
import { Assignment } from './models/assignment.model';
|
|
import { Constraint } from './models/constraint.model';
|
|
import { Planning } from './models/planning.model';
|
|
import { RunwaySpacing } from './models/runwayspacing.model';
|
|
import { Waypoint } from '../generic/models/waypoint.model';
|
|
import { WaypointDto } from '../generic/dto/waypoint.dto';
|
|
import { Coordinate } from '../generic/models/coordinate.model';
|
|
import { CoordinateDto } from '../generic/dto/coordinate.dto';
|
|
import { CoordinateConverter, WaypointConverter } from '../generic/converters';
|
|
import { ActiveRunwaysDto } from './dto/activerunways.dto';
|
|
import { Runway } from './models/runway.model';
|
|
import { RunwayDto } from './dto/runway.dto';
|
|
|
|
@Controller('airport')
|
|
export class AirportController {
|
|
constructor(private readonly airportService: AirportService) {}
|
|
|
|
private static convertConstraint<T>(
|
|
constraint: Constraint | ConstraintDto,
|
|
): T {
|
|
return {
|
|
waypoint: constraint.waypoint,
|
|
altitude: {
|
|
constraint: constraint.altitude.constraint,
|
|
mode: constraint.altitude.mode,
|
|
},
|
|
speed: {
|
|
constraint: constraint.speed.constraint,
|
|
mode: constraint.speed.mode,
|
|
},
|
|
} as T;
|
|
}
|
|
|
|
private static convertConstraints<T>(
|
|
constraints: Constraint[] | ConstraintDto[],
|
|
): T[] {
|
|
const retval: T[] = [];
|
|
constraints.forEach((constraint) =>
|
|
retval.push(AirportController.convertConstraint<T>(constraint)),
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
private static convertArrivalRoutes<T, C, W, WC>(
|
|
routes: ArrivalRoute[] | ArrivalRouteDto[],
|
|
): T[] {
|
|
const retval: T[] = [];
|
|
routes.forEach((route) =>
|
|
retval.push({
|
|
arrival: route.runway,
|
|
runway: route.runway,
|
|
waypoints: WaypointConverter.convertList<W, WC>(route.waypoints),
|
|
constraints: AirportController.convertConstraints<C>(route.constraints),
|
|
} as T),
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
private static convertRunwaySpacings<T>(
|
|
spacings: RunwaySpacing[] | RunwaySpacingDto[],
|
|
): T[] {
|
|
const retval: T[] = [];
|
|
spacings.forEach((spacing) =>
|
|
retval.push({
|
|
runway: spacing.runway,
|
|
spacing: spacing.spacing,
|
|
} as T),
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
private static convertAssignments<T>(
|
|
assignments: Assignment[] | AssignmentDto[],
|
|
): T[] {
|
|
const retval: T[] = [];
|
|
assignments.forEach((assignment) =>
|
|
retval.push({
|
|
runway: assignment.runway,
|
|
type: assignment.type,
|
|
aircrafts: assignment.aircrafts,
|
|
assignedStands: assignment.assignedStands,
|
|
} as T),
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
private static convertPlanning<T, U>(planning: Planning | PlanningDto): T {
|
|
return {
|
|
optimization: {
|
|
windowSize: planning.optimization.windowSize,
|
|
windowOverlap: planning.optimization.windowOverlap,
|
|
fixedBeforeInitialApproachFix:
|
|
planning.optimization.fixedBeforeInitialApproachFix,
|
|
maximumAirportDistance: planning.optimization.maximumAirportDistance,
|
|
},
|
|
assignments: AirportController.convertAssignments<U>(
|
|
planning.assignments,
|
|
),
|
|
} as T;
|
|
}
|
|
|
|
private static convertRunways<T>(runways: Runway[] | RunwayDto[]): T[] {
|
|
const retval: T[] = [];
|
|
runways.forEach((runway) =>
|
|
retval.push({
|
|
identifier: runway.identifier,
|
|
threshold: CoordinateConverter.convert(runway.threshold),
|
|
} as T),
|
|
);
|
|
return retval;
|
|
}
|
|
|
|
private static airportToAirportDto(airport: Airport): AirportDto {
|
|
if (!airport) return null;
|
|
|
|
return {
|
|
icao: airport.icao,
|
|
location: WaypointConverter.convert<WaypointDto, CoordinateDto>(
|
|
airport.location,
|
|
),
|
|
elevation: airport.elevation,
|
|
runways: AirportController.convertRunways(airport.runways),
|
|
upperConstraints: AirportController.convertConstraints<ConstraintDto>(
|
|
airport.upperConstraints,
|
|
),
|
|
arrivalRoutes: AirportController.convertArrivalRoutes<
|
|
ArrivalRouteDto,
|
|
ConstraintDto,
|
|
WaypointDto,
|
|
CoordinateDto
|
|
>(airport.arrivalRoutes),
|
|
spacings: AirportController.convertRunwaySpacings<RunwaySpacingDto>(
|
|
airport.spacings,
|
|
),
|
|
planning: AirportController.convertPlanning<PlanningDto, AssignmentDto>(
|
|
airport.planning,
|
|
),
|
|
activeRunways: airport.activeRunways,
|
|
arrivalMode: airport.arrivalMode,
|
|
};
|
|
}
|
|
|
|
private static airportDtoToAirport(airport: AirportDto): Airport {
|
|
if (!airport) return null;
|
|
|
|
return {
|
|
icao: airport.icao,
|
|
location: WaypointConverter.convert<Waypoint, Coordinate>(
|
|
airport.location,
|
|
),
|
|
elevation: airport.elevation,
|
|
runways: AirportController.convertRunways(airport.runways),
|
|
upperConstraints: AirportController.convertConstraints<Constraint>(
|
|
airport.upperConstraints,
|
|
),
|
|
arrivalRoutes: AirportController.convertArrivalRoutes<
|
|
ArrivalRoute,
|
|
Constraint,
|
|
Waypoint,
|
|
Coordinate
|
|
>(airport.arrivalRoutes),
|
|
spacings: AirportController.convertRunwaySpacings<RunwaySpacing>(
|
|
airport.spacings,
|
|
),
|
|
planning: AirportController.convertPlanning<Planning, Assignment>(
|
|
airport.planning,
|
|
),
|
|
activeRunways: airport.activeRunways,
|
|
arrivalMode: airport.arrivalMode,
|
|
};
|
|
}
|
|
|
|
private static validateAirportEnums(airport: AirportDto): void {
|
|
airport.planning.assignments.forEach((assignment) => {
|
|
if (
|
|
assignment.type !== 'SHALL' &&
|
|
assignment.type !== 'SHOULD' &&
|
|
assignment.type !== 'MAY'
|
|
) {
|
|
throw new HttpException(
|
|
'Invalid assignment type',
|
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
private static validateConstraint(constraint: ConstraintDto): void {
|
|
if (
|
|
constraint.altitude.mode !== 'BELOW' &&
|
|
constraint.altitude.mode !== 'EXACT' &&
|
|
constraint.altitude.mode !== 'ABOVE'
|
|
) {
|
|
throw new HttpException(
|
|
'Invalid altitude constraint mode',
|
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
|
);
|
|
}
|
|
if (
|
|
constraint.speed.mode !== 'BELOW' &&
|
|
constraint.speed.mode !== 'EXACT' &&
|
|
constraint.speed.mode !== 'ABOVE'
|
|
) {
|
|
throw new HttpException(
|
|
'Invalid speed constraint mode',
|
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
|
);
|
|
}
|
|
}
|
|
|
|
private static validateAirportConstraints(airport: AirportDto): void {
|
|
airport.upperConstraints.forEach((constraint) =>
|
|
AirportController.validateConstraint(constraint),
|
|
);
|
|
|
|
airport.arrivalRoutes.forEach((route) => {
|
|
route.constraints.forEach((constraint) =>
|
|
AirportController.validateConstraint(constraint),
|
|
);
|
|
});
|
|
}
|
|
|
|
@Get('/allCodes')
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'All available airports',
|
|
type: [String],
|
|
})
|
|
async allCodes(): Promise<string[]> {
|
|
return this.airportService.airportsList();
|
|
}
|
|
|
|
@Get('/get')
|
|
@ApiQuery({
|
|
name: 'icao',
|
|
description: 'The ICAO code of the airport',
|
|
type: String,
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'The airport configuration',
|
|
type: [AirportDto],
|
|
})
|
|
@ApiResponse({
|
|
status: 404,
|
|
description: 'No airport found',
|
|
})
|
|
async get(@Query('icao') icao: string): Promise<AirportDto> {
|
|
return this.airportService.airport(icao).then((airport) => {
|
|
if (!airport) {
|
|
throw new HttpException('Airport not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
return AirportController.airportToAirportDto(airport);
|
|
});
|
|
}
|
|
|
|
@Post('/register')
|
|
@ApiBody({
|
|
description: 'The airport definition',
|
|
type: AirportDto,
|
|
})
|
|
@ApiResponse({
|
|
status: 201,
|
|
description: 'The airport is registered',
|
|
})
|
|
@ApiResponse({
|
|
status: 409,
|
|
description: 'The airport is already registered',
|
|
})
|
|
@ApiResponse({
|
|
status: 422,
|
|
description: 'The assignment type is invalid',
|
|
})
|
|
@ApiResponse({
|
|
status: 422,
|
|
description: 'The constraint type is invalid',
|
|
})
|
|
async register(@Body('airport') airport: AirportDto): Promise<void> {
|
|
AirportController.validateAirportConstraints(airport);
|
|
AirportController.validateAirportEnums(airport);
|
|
|
|
await this.airportService
|
|
.registerAirport(AirportController.airportDtoToAirport(airport))
|
|
.then((registered) => {
|
|
if (!registered) {
|
|
throw new HttpException(
|
|
'Airport already available',
|
|
HttpStatus.CONFLICT,
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Delete('/remove')
|
|
@ApiQuery({
|
|
name: 'icao',
|
|
description: 'The ICAO code of the airport',
|
|
type: String,
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'All log entries are deleted',
|
|
})
|
|
@ApiResponse({
|
|
status: 404,
|
|
description: 'Could not find the airport',
|
|
})
|
|
async remove(@Query('icao') icao: string): Promise<void> {
|
|
await this.airportService.airport(icao).then(async (airport) => {
|
|
if (!airport) {
|
|
throw new HttpException('Airport not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
await this.airportService.deleteAirport(icao);
|
|
});
|
|
}
|
|
|
|
@Patch('/activateRunways')
|
|
@ApiBody({
|
|
description: 'The airport definition',
|
|
type: ActiveRunwaysDto,
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'The active runways are set',
|
|
})
|
|
@ApiResponse({
|
|
status: 404,
|
|
description: 'The airport or the runways are not found',
|
|
})
|
|
@ApiResponse({
|
|
status: 422,
|
|
description: 'The arrival mode is invalid',
|
|
})
|
|
async activeRunways(
|
|
@Body('runways') runways: ActiveRunwaysDto,
|
|
): Promise<void> {
|
|
if (runways.mode !== 'STAGGERED' && runways.mode !== 'IPA') {
|
|
throw new HttpException(
|
|
'Invalid arrival mode',
|
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
|
);
|
|
}
|
|
|
|
await this.airportService.activateRunways(runways).then((updated) => {
|
|
if (!updated) {
|
|
throw new HttpException('Airport not found', HttpStatus.NOT_FOUND);
|
|
}
|
|
});
|
|
}
|
|
}
|