introduce the database and controller connections for all inbounds
This commit is contained in:
@@ -25,9 +25,9 @@ export class AirportService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async airport(icao: string): Promise<Airport> {
|
async airport(icao: string): Promise<Airport> {
|
||||||
return this.airportModel.find({ icao }).then((response) => {
|
return this.airportModel.findOne({ icao }).then((response) => {
|
||||||
if (!response || response.length !== 1) return null;
|
if (!response) return null;
|
||||||
return response[0];
|
return response;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { AirportModule } from './airport/airport.module';
|
|||||||
import { LoggingModule } from './logging/logging.module';
|
import { LoggingModule } from './logging/logging.module';
|
||||||
import { LoggingController } from './logging/logging.controller';
|
import { LoggingController } from './logging/logging.controller';
|
||||||
import { AirportController } from './airport/airport.controller';
|
import { AirportController } from './airport/airport.controller';
|
||||||
|
import { InboundModule } from './inbound/inbound.module';
|
||||||
|
import { InboundController } from './inbound/inbound.controller';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -30,7 +32,8 @@ import { AirportController } from './airport/airport.controller';
|
|||||||
PerformanceModule,
|
PerformanceModule,
|
||||||
AirportModule,
|
AirportModule,
|
||||||
LoggingModule,
|
LoggingModule,
|
||||||
|
InboundModule,
|
||||||
],
|
],
|
||||||
controllers: [LoggingController, AirportController],
|
controllers: [LoggingController, AirportController, InboundController],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
44
src/inbound/dto/aircraft.dto.ts
Normal file
44
src/inbound/dto/aircraft.dto.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { IsNotEmpty, Length, IsInt, Min, Max } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class AircraftDto {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The ICAO code of the aircraft',
|
||||||
|
example: 'A359',
|
||||||
|
})
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The Wake Turbulence Category (possible: L, M, H, S)',
|
||||||
|
example: 'M',
|
||||||
|
})
|
||||||
|
@Length(1)
|
||||||
|
wtc: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The Wake Turbulence Category (possible: A, B, C, D, E, F)',
|
||||||
|
example: 'C',
|
||||||
|
})
|
||||||
|
@Length(1)
|
||||||
|
wakeRecat: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The number of engines',
|
||||||
|
example: 2,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@Min(1)
|
||||||
|
@Max(6)
|
||||||
|
engineCount: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The engine type (possible: ELECTRIC, TURBOPROP, JET)',
|
||||||
|
example: 'JET',
|
||||||
|
})
|
||||||
|
engineType: string;
|
||||||
|
}
|
||||||
32
src/inbound/dto/controllerinput.dto.ts
Normal file
32
src/inbound/dto/controllerinput.dto.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { IsNotEmpty, IsOptional, IsDateString } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { WaypointDto } from '../../generic/dto/waypoint.dto';
|
||||||
|
|
||||||
|
export class ControllerInputDto {
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The timestamp of the last report',
|
||||||
|
})
|
||||||
|
@IsDateString()
|
||||||
|
reportedTime: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The remaining route of the inbound',
|
||||||
|
})
|
||||||
|
remainingRoute: WaypointDto[];
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The requested runway by the pilot',
|
||||||
|
example: '25L',
|
||||||
|
})
|
||||||
|
requestedRunway: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned stand after landing',
|
||||||
|
example: 'A05',
|
||||||
|
})
|
||||||
|
plannedStand: string;
|
||||||
|
}
|
||||||
49
src/inbound/dto/flightstate.dto.ts
Normal file
49
src/inbound/dto/flightstate.dto.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { IsNotEmpty, IsInt, Min, Max } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { CoordinateDto } from '../../generic/dto/coordinate.dto';
|
||||||
|
|
||||||
|
export class FlightStateDto {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The current position',
|
||||||
|
})
|
||||||
|
position: CoordinateDto;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The reported ground speed',
|
||||||
|
example: 400,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@Max(700)
|
||||||
|
groundSpeed: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The reported ground track',
|
||||||
|
example: 400,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@Max(360)
|
||||||
|
groundTrack: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The reported altitude',
|
||||||
|
example: 30000,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@Max(60000)
|
||||||
|
altitude: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The reported vertical speed',
|
||||||
|
example: 400,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
verticalSpeed: number;
|
||||||
|
}
|
||||||
56
src/inbound/dto/inbound.dto.ts
Normal file
56
src/inbound/dto/inbound.dto.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { IsNotEmpty, IsOptional, Length } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { AircraftDto } from './aircraft.dto';
|
||||||
|
import { ControllerInputDto } from './controllerinput.dto';
|
||||||
|
import { FlightStateDto } from './flightstate.dto';
|
||||||
|
import { PlanningDto } from './planning.dto';
|
||||||
|
|
||||||
|
export class InboundDto {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The used callsign',
|
||||||
|
example: 'DLH3PM',
|
||||||
|
})
|
||||||
|
callsign: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The filed destination',
|
||||||
|
example: 'EDDB',
|
||||||
|
})
|
||||||
|
@Length(4)
|
||||||
|
destination: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description:
|
||||||
|
'The reported controller level (possible: UNK, DEL, GRD, TWR, APP, DEP, CTR)',
|
||||||
|
example: 'EDDB',
|
||||||
|
})
|
||||||
|
@Length(3)
|
||||||
|
reporter: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The used aircraft',
|
||||||
|
})
|
||||||
|
aircraft: AircraftDto;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The current flight state',
|
||||||
|
})
|
||||||
|
flightState: FlightStateDto;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The data given by the controller',
|
||||||
|
})
|
||||||
|
controllerData: ControllerInputDto;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned arrival',
|
||||||
|
})
|
||||||
|
plan: PlanningDto;
|
||||||
|
}
|
||||||
31
src/inbound/dto/planning.dto.ts
Normal file
31
src/inbound/dto/planning.dto.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { IsNotEmpty } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { PredictedWaypointDto } from './predictedwaypoint.dto';
|
||||||
|
|
||||||
|
export class PlanningDto {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned arrival route',
|
||||||
|
example: 'KETAP25L',
|
||||||
|
})
|
||||||
|
arrivalRoute: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned arrival runway',
|
||||||
|
example: '25L',
|
||||||
|
})
|
||||||
|
arrivalRunway: string;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned route',
|
||||||
|
})
|
||||||
|
plannedRoute: PredictedWaypointDto[];
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Indicates if the plan is fixed',
|
||||||
|
})
|
||||||
|
fixedPlan: boolean;
|
||||||
|
}
|
||||||
49
src/inbound/dto/predictedwaypoint.dto.ts
Normal file
49
src/inbound/dto/predictedwaypoint.dto.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { IsNotEmpty, IsInt, Min, Max } from 'class-validator';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { WaypointDto } from 'src/generic/dto/waypoint.dto';
|
||||||
|
|
||||||
|
export class PredictedWaypointDto {
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The waypoint',
|
||||||
|
})
|
||||||
|
waypoint: WaypointDto;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned altitude',
|
||||||
|
example: 23000,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@Max(60000)
|
||||||
|
altitude: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned indicated airspeed',
|
||||||
|
example: 200,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@Max(600)
|
||||||
|
indicatedAirspeed: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned groundspeed',
|
||||||
|
example: 500,
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@Max(800)
|
||||||
|
groundspeed: number;
|
||||||
|
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The planned time overhead the waypoint',
|
||||||
|
example: 'Wed, 14 Jun 2017 07:00:00z',
|
||||||
|
})
|
||||||
|
@IsInt()
|
||||||
|
plannedOverheadTime: string;
|
||||||
|
}
|
||||||
18
src/inbound/inbound.controller.spec.ts
Normal file
18
src/inbound/inbound.controller.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { InboundController } from './inbound.controller';
|
||||||
|
|
||||||
|
describe('InboundController', () => {
|
||||||
|
let controller: InboundController;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [InboundController],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<InboundController>(InboundController);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(controller).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
213
src/inbound/inbound.controller.ts
Normal file
213
src/inbound/inbound.controller.ts
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Delete,
|
||||||
|
Post,
|
||||||
|
Query,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { ApiBody, ApiQuery, ApiResponse } from '@nestjs/swagger';
|
||||||
|
import { AirportService } from 'src/airport/airport.service';
|
||||||
|
import { CoordinateConverter, WaypointConverter } from 'src/generic/converters';
|
||||||
|
import { CoordinateDto } from 'src/generic/dto/coordinate.dto';
|
||||||
|
import { WaypointDto } from 'src/generic/dto/waypoint.dto';
|
||||||
|
import { AircraftDto } from './dto/aircraft.dto';
|
||||||
|
import { ControllerInputDto } from './dto/controllerinput.dto';
|
||||||
|
import { FlightStateDto } from './dto/flightstate.dto';
|
||||||
|
import { InboundDto } from './dto/inbound.dto';
|
||||||
|
import { PlanningDto } from './dto/planning.dto';
|
||||||
|
import { PredictedWaypointDto } from './dto/predictedwaypoint.dto';
|
||||||
|
import { InboundService } from './inbound.service';
|
||||||
|
import { Aircraft } from './models/aircraft.model';
|
||||||
|
import { ControllerInput } from './models/controllerinput.model';
|
||||||
|
import { FlightState } from './models/flightstate.model';
|
||||||
|
import { Inbound } from './models/inbound.model';
|
||||||
|
import { Planning } from './models/planning.model';
|
||||||
|
import { PredictedWaypoint } from './models/predictedwaypoint.model';
|
||||||
|
|
||||||
|
@Controller('inbound')
|
||||||
|
export class InboundController {
|
||||||
|
constructor(
|
||||||
|
private readonly inboundService: InboundService,
|
||||||
|
private readonly airportService: AirportService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
private static convertAircraft<T>(aircraft: Aircraft | AircraftDto): T {
|
||||||
|
return {
|
||||||
|
type: aircraft.type,
|
||||||
|
wtc: aircraft.wtc,
|
||||||
|
wakeRecat: aircraft.wakeRecat,
|
||||||
|
engineCount: aircraft.engineCount,
|
||||||
|
engineType: aircraft.engineType,
|
||||||
|
} as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static convertControllerInput<T>(
|
||||||
|
input: ControllerInput | ControllerInputDto,
|
||||||
|
): T {
|
||||||
|
return {
|
||||||
|
reportedTime: input.reportedTime,
|
||||||
|
remainingRoute: WaypointConverter.convertList(input.remainingRoute),
|
||||||
|
requestedRunway: input.requestedRunway,
|
||||||
|
plannedStand: input.plannedStand,
|
||||||
|
} as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static convertFlightState<T>(input: FlightState | FlightStateDto): T {
|
||||||
|
return {
|
||||||
|
position: CoordinateConverter.convert(input.position),
|
||||||
|
groundSpeed: input.groundSpeed,
|
||||||
|
groundTrack: input.groundTrack,
|
||||||
|
altitude: input.altitude,
|
||||||
|
verticalSpeed: input.verticalSpeed,
|
||||||
|
} as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static convertPredictedWaypoints(
|
||||||
|
waypoints: PredictedWaypoint[],
|
||||||
|
): PredictedWaypointDto[] {
|
||||||
|
const retval: PredictedWaypointDto[] = [];
|
||||||
|
waypoints.forEach((input) =>
|
||||||
|
retval.push({
|
||||||
|
waypoint: WaypointConverter.convert<WaypointDto, CoordinateDto>(
|
||||||
|
input.waypoint,
|
||||||
|
),
|
||||||
|
altitude: input.altitude,
|
||||||
|
indicatedAirspeed: input.indicatedAirspeed,
|
||||||
|
groundspeed: input.groundspeed,
|
||||||
|
plannedOverheadTime: input.plannedOverheadTime,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static convertPlanning(plan: Planning): PlanningDto {
|
||||||
|
if (plan === undefined) return undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
arrivalRoute: plan.arrivalRoute,
|
||||||
|
arrivalRunway: plan.arrivalRunway,
|
||||||
|
plannedRoute: InboundController.convertPredictedWaypoints(
|
||||||
|
plan.plannedRoute,
|
||||||
|
),
|
||||||
|
fixedPlan: plan.fixedPlan,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static convertInboundToInboundDto(inbound: Inbound): InboundDto {
|
||||||
|
return {
|
||||||
|
callsign: inbound.callsign,
|
||||||
|
destination: inbound.destination,
|
||||||
|
reporter: inbound.reporter,
|
||||||
|
aircraft: InboundController.convertAircraft(inbound.aircraft),
|
||||||
|
flightState: InboundController.convertFlightState(inbound.flightState),
|
||||||
|
controllerData: InboundController.convertControllerInput(
|
||||||
|
inbound.controllerData,
|
||||||
|
),
|
||||||
|
plan: InboundController.convertPlanning(inbound.plan),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static convertInboundDtoInbound(inbound: InboundDto): Inbound {
|
||||||
|
return {
|
||||||
|
callsign: inbound.callsign,
|
||||||
|
destination: inbound.destination,
|
||||||
|
reporter: inbound.reporter,
|
||||||
|
aircraft: InboundController.convertAircraft(inbound.aircraft),
|
||||||
|
flightState: InboundController.convertFlightState(inbound.flightState),
|
||||||
|
controllerData: InboundController.convertControllerInput(
|
||||||
|
inbound.controllerData,
|
||||||
|
),
|
||||||
|
plan: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/inbounds')
|
||||||
|
@ApiQuery({
|
||||||
|
name: 'icao',
|
||||||
|
description: 'The ICAO code of the airport',
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'All known inbounds',
|
||||||
|
type: [InboundDto],
|
||||||
|
})
|
||||||
|
async inbounds(@Query('icao') icao: string): Promise<InboundDto[]> {
|
||||||
|
return this.inboundService.airportInbounds(icao).then((inbounds) => {
|
||||||
|
if (!inbounds) {
|
||||||
|
throw new HttpException(
|
||||||
|
'No inbounds for the airport found',
|
||||||
|
HttpStatus.NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const retval: InboundDto[] = [];
|
||||||
|
inbounds.forEach((inbound) =>
|
||||||
|
retval.push(InboundController.convertInboundToInboundDto(inbound)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/insert')
|
||||||
|
@ApiBody({
|
||||||
|
description: 'The new or updated inbound',
|
||||||
|
type: InboundDto,
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: 201,
|
||||||
|
description: 'Inserted or updated the inbound',
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: 404,
|
||||||
|
description: 'The destination airport is unknown',
|
||||||
|
})
|
||||||
|
async insert(inbound: InboundDto): Promise<boolean> {
|
||||||
|
return this.airportService.airport(inbound.destination).then((airport) => {
|
||||||
|
if (!airport) {
|
||||||
|
throw new HttpException('Airport not found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.inboundService
|
||||||
|
.callsignKnown(inbound.callsign)
|
||||||
|
.then((known) => {
|
||||||
|
const internalInbound =
|
||||||
|
InboundController.convertInboundDtoInbound(inbound);
|
||||||
|
|
||||||
|
if (known) {
|
||||||
|
return this.inboundService.update(internalInbound);
|
||||||
|
} else {
|
||||||
|
return this.inboundService.add(internalInbound);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete('/remove')
|
||||||
|
@ApiQuery({
|
||||||
|
name: 'callsign',
|
||||||
|
description: 'The callsign of the inbound',
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: 200,
|
||||||
|
description: 'The inbound is deleted',
|
||||||
|
})
|
||||||
|
@ApiResponse({
|
||||||
|
status: 404,
|
||||||
|
description: 'The inbound is unknown',
|
||||||
|
})
|
||||||
|
async remove(@Query('callsign') callsign: string): Promise<void> {
|
||||||
|
await this.inboundService.callsignKnown(callsign).then(async (known) => {
|
||||||
|
if (!known) {
|
||||||
|
throw new HttpException('Inbound not found', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.inboundService.remove(callsign);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/inbound/inbound.module.ts
Normal file
17
src/inbound/inbound.module.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { MongooseModule } from '@nestjs/mongoose';
|
||||||
|
import { InboundSchema } from './models/inbound.model';
|
||||||
|
import { InboundService } from './inbound.service';
|
||||||
|
import { InboundController } from './inbound.controller';
|
||||||
|
import { AirportModule } from 'src/airport/airport.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
MongooseModule.forFeature([{ name: 'inbound', schema: InboundSchema }]),
|
||||||
|
AirportModule,
|
||||||
|
],
|
||||||
|
providers: [InboundService],
|
||||||
|
controllers: [InboundController],
|
||||||
|
exports: [MongooseModule, InboundService],
|
||||||
|
})
|
||||||
|
export class InboundModule {}
|
||||||
18
src/inbound/inbound.service.spec.ts
Normal file
18
src/inbound/inbound.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { InboundService } from './inbound.service';
|
||||||
|
|
||||||
|
describe('InboundService', () => {
|
||||||
|
let service: InboundService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [InboundService],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<InboundService>(InboundService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(service).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
61
src/inbound/inbound.service.ts
Normal file
61
src/inbound/inbound.service.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectModel } from '@nestjs/mongoose';
|
||||||
|
import { Model } from 'mongoose';
|
||||||
|
import { Inbound, InboundDocument } from './models/inbound.model';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class InboundService {
|
||||||
|
constructor(
|
||||||
|
@InjectModel('inbound')
|
||||||
|
private readonly inboundModel: Model<InboundDocument>,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async callsignKnown(callsign: string): Promise<boolean> {
|
||||||
|
return this.inboundModel
|
||||||
|
.findOne({ callsign })
|
||||||
|
.then((inbound) => inbound !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async add(inbound: Inbound): Promise<boolean> {
|
||||||
|
return this.callsignKnown(inbound.callsign).then(async (known) => {
|
||||||
|
if (known) return false;
|
||||||
|
|
||||||
|
// modify the inbound data
|
||||||
|
inbound.plan = undefined;
|
||||||
|
inbound.controllerData.reportedTime = new Date().toUTCString();
|
||||||
|
|
||||||
|
await this.inboundModel.create(inbound);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(callsign: string): Promise<boolean> {
|
||||||
|
return this.callsignKnown(callsign).then(async (known) => {
|
||||||
|
if (!known) return false;
|
||||||
|
await this.inboundModel.deleteOne({ callsign });
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(inbound: Inbound): Promise<boolean> {
|
||||||
|
return this.callsignKnown(inbound.callsign).then(async (known) => {
|
||||||
|
if (!known) return false;
|
||||||
|
|
||||||
|
// modify the inbound data
|
||||||
|
inbound.plan = undefined;
|
||||||
|
inbound.controllerData.reportedTime = new Date().toUTCString();
|
||||||
|
|
||||||
|
await this.inboundModel.findOneAndUpdate(
|
||||||
|
{ callsign: inbound.callsign },
|
||||||
|
inbound,
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async airportInbounds(icao: string): Promise<Inbound[]> {
|
||||||
|
return this.inboundModel.find({ destination: icao });
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/inbound/models/aircraft.model.ts
Normal file
42
src/inbound/models/aircraft.model.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
|
||||||
|
export type AircraftDocument = Aircraft & Document;
|
||||||
|
|
||||||
|
@Schema()
|
||||||
|
export class Aircraft {
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
enum: ['L', 'M', 'H', 'S'],
|
||||||
|
})
|
||||||
|
wtc: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
enum: ['A', 'B', 'C', 'D', 'E', 'F'],
|
||||||
|
})
|
||||||
|
wakeRecat: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
engineCount: number;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
enum: ['ELECTRIC', 'TURBOPROP', 'JET'],
|
||||||
|
})
|
||||||
|
engineType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const AircraftSchema = SchemaFactory.createForClass(Aircraft);
|
||||||
32
src/inbound/models/controllerinput.model.ts
Normal file
32
src/inbound/models/controllerinput.model.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
import { Waypoint, WaypointSchema } from 'src/generic/models/waypoint.model';
|
||||||
|
|
||||||
|
export type ControllerInputDocument = ControllerInput & Document;
|
||||||
|
|
||||||
|
@Schema()
|
||||||
|
export class ControllerInput {
|
||||||
|
@Prop({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
reportedTime: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: [WaypointSchema],
|
||||||
|
})
|
||||||
|
remainingRoute: Waypoint[];
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
requestedRunway: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
plannedStand: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ControllerInputSchema =
|
||||||
|
SchemaFactory.createForClass(ControllerInput);
|
||||||
43
src/inbound/models/flightstate.model.ts
Normal file
43
src/inbound/models/flightstate.model.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
import {
|
||||||
|
Coordinate,
|
||||||
|
CoordinateSchema,
|
||||||
|
} from '../../generic/models/coordinate.model';
|
||||||
|
|
||||||
|
export type FlightStateDocument = FlightState & Document;
|
||||||
|
|
||||||
|
@Schema()
|
||||||
|
export class FlightState {
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: CoordinateSchema,
|
||||||
|
})
|
||||||
|
position: Coordinate;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
groundSpeed: number;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
groundTrack: number;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
altitude: number;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
verticalSpeed: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FlightStateSchema = SchemaFactory.createForClass(FlightState);
|
||||||
59
src/inbound/models/inbound.model.ts
Normal file
59
src/inbound/models/inbound.model.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
import { Aircraft, AircraftSchema } from './aircraft.model';
|
||||||
|
import {
|
||||||
|
ControllerInput,
|
||||||
|
ControllerInputSchema,
|
||||||
|
} from './controllerinput.model';
|
||||||
|
import { FlightState, FlightStateSchema } from './flightstate.model';
|
||||||
|
import { Planning, PlanningSchema } from './planning.model';
|
||||||
|
|
||||||
|
export type InboundDocument = Inbound & Document;
|
||||||
|
|
||||||
|
@Schema()
|
||||||
|
export class Inbound {
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
callsign: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
index: true,
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
destination: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
enum: ['UNK', 'DEL', 'GRD', 'TWR', 'APP', 'DEP', 'CTR'],
|
||||||
|
})
|
||||||
|
reporter: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: AircraftSchema,
|
||||||
|
})
|
||||||
|
aircraft: Aircraft;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: FlightStateSchema,
|
||||||
|
})
|
||||||
|
flightState: FlightState;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
type: ControllerInputSchema,
|
||||||
|
})
|
||||||
|
controllerData: ControllerInput;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
type: PlanningSchema,
|
||||||
|
})
|
||||||
|
plan: Planning;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InboundSchema = SchemaFactory.createForClass(Inbound);
|
||||||
37
src/inbound/models/planning.model.ts
Normal file
37
src/inbound/models/planning.model.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
import {
|
||||||
|
PredictedWaypoint,
|
||||||
|
PredictedWaypointSchema,
|
||||||
|
} from './predictedwaypoint.model';
|
||||||
|
|
||||||
|
export type PlanningDocument = Planning & Document;
|
||||||
|
|
||||||
|
@Schema()
|
||||||
|
export class Planning {
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
arrivalRoute: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
arrivalRunway: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: [PredictedWaypointSchema],
|
||||||
|
})
|
||||||
|
plannedRoute: PredictedWaypoint[];
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Boolean,
|
||||||
|
})
|
||||||
|
fixedPlan: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PlanningSchema = SchemaFactory.createForClass(Planning);
|
||||||
41
src/inbound/models/predictedwaypoint.model.ts
Normal file
41
src/inbound/models/predictedwaypoint.model.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
import { Waypoint, WaypointSchema } from '../../generic/models/waypoint.model';
|
||||||
|
|
||||||
|
export type PredictedWaypointDocument = PredictedWaypoint & Document;
|
||||||
|
|
||||||
|
@Schema()
|
||||||
|
export class PredictedWaypoint {
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: WaypointSchema,
|
||||||
|
})
|
||||||
|
waypoint: Waypoint;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
altitude: number;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
indicatedAirspeed: number;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: Number,
|
||||||
|
})
|
||||||
|
groundspeed: number;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
})
|
||||||
|
plannedOverheadTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PredictedWaypointSchema =
|
||||||
|
SchemaFactory.createForClass(PredictedWaypoint);
|
||||||
Reference in New Issue
Block a user