96 switch from azure table storage to sqlite (#97)
* adding typeorm to api * switching to sqlite * switching to sqlite * switching to sqlite * migrating to sqlite * updating terraform * updating infrastructure
This commit was merged in pull request #97.
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
export class Certificate {
|
||||
type: string;
|
||||
issueDate: string;
|
||||
number: string;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export class Endorsement {
|
||||
type: string;
|
||||
issueDate: Date;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
||||
import { Observable, map } from 'rxjs';
|
||||
|
||||
export class PilotInterceptor implements NestInterceptor {
|
||||
intercept(context: ExecutionContext, handler: CallHandler): Observable<any> {
|
||||
const req = context.switchToHttp().getRequest();
|
||||
const authHeader = req.headers.authorization;
|
||||
const token = authHeader && authHeader.split(' ')[1];
|
||||
|
||||
if (!token) {
|
||||
return handler.handle().pipe(
|
||||
map((data) => {
|
||||
if (data.length) {
|
||||
const pilots = data.map((pilot) => {
|
||||
return {
|
||||
partitionKey: pilot.partitionKey,
|
||||
rowKey: pilot.rowKey,
|
||||
id: pilot.id,
|
||||
name: pilot.name,
|
||||
certificates: pilot.certificates,
|
||||
endorsements: pilot.endorsements
|
||||
};
|
||||
});
|
||||
|
||||
return pilots;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return handler.handle().pipe(map((data) => data));
|
||||
}
|
||||
}
|
||||
@@ -11,24 +11,24 @@ import {
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { PilotDto } from './pilot.dto';
|
||||
import { Pilot } from './pilot.entity';
|
||||
import { PilotService } from './pilot.service';
|
||||
import { CustomError } from '../error/customError';
|
||||
import { AuthGuard } from '@noahspan/noahspan-modules'
|
||||
import { PilotInterceptor } from './interceptors/pilot.interceptor';
|
||||
import { PilotInterceptor } from './pilot.interceptor';
|
||||
import { AuthGuard, Public } from '@noahspan/noahspan-modules';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
|
||||
const reflector = new Reflector();
|
||||
|
||||
@Controller('pilots')
|
||||
@UseInterceptors(new PilotInterceptor())
|
||||
@UseInterceptors(new PilotInterceptor(reflector))
|
||||
export class PilotController {
|
||||
constructor(private readonly pilotService: PilotService) {}
|
||||
|
||||
@Get(':partitionKey/:rowKey')
|
||||
async find(
|
||||
@Param('partitionKey') partitionKey: string,
|
||||
@Param('rowKey') rowKey: string
|
||||
) {
|
||||
@Get(':id')
|
||||
@Public()
|
||||
async find(@Param('id') id: string) {
|
||||
try {
|
||||
return await this.pilotService.find(partitionKey, rowKey);
|
||||
return await this.pilotService.find(id);
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
|
||||
@@ -37,75 +37,39 @@ export class PilotController {
|
||||
}
|
||||
|
||||
@Get()
|
||||
@Public()
|
||||
async findAll() {
|
||||
try {
|
||||
return await this.pilotService.findAll();
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
|
||||
console.log(error)
|
||||
throw new HttpException(customError.message, customError.statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@UseGuards(AuthGuard)
|
||||
@Post()
|
||||
@UseGuards(AuthGuard)
|
||||
async create(@Body() pilotDto: PilotDto) {
|
||||
try {
|
||||
let pilot = new Pilot();
|
||||
|
||||
pilot = {
|
||||
partitionKey: pilotDto.partitionKey,
|
||||
rowKey: pilotDto.rowKey,
|
||||
id: pilotDto.id,
|
||||
name: pilotDto.name,
|
||||
address: pilotDto.address,
|
||||
city: pilotDto.city,
|
||||
state: pilotDto.state,
|
||||
postalCode: pilotDto.postalCode,
|
||||
email: pilotDto.email,
|
||||
phone: pilotDto.phone,
|
||||
medicalClass: pilotDto.medicalClass,
|
||||
medicalExpiration: pilotDto.medicalExpiration,
|
||||
certificates: JSON.stringify(pilotDto.certificates),
|
||||
endorsements: JSON.stringify(pilotDto.endorsements)
|
||||
}
|
||||
|
||||
return await this.pilotService.create(pilot);
|
||||
return await this.pilotService.create(pilotDto);
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
console.log(error)
|
||||
// const customError = error as CustomError;
|
||||
|
||||
throw new HttpException(customError.message, customError.statusCode);
|
||||
// throw new HttpException(customError.message, customError.statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':id')
|
||||
@UseGuards(AuthGuard)
|
||||
@Put(':partitionKey/:rowKey')
|
||||
async update(
|
||||
@Param('partitionKey') partitionKey: string,
|
||||
@Param('rowKey') rowKey: string,
|
||||
@Param('id') id: string,
|
||||
@Body() pilotDto: PilotDto
|
||||
) {
|
||||
try {
|
||||
let pilot = new Pilot();
|
||||
|
||||
pilot = {
|
||||
partitionKey: pilotDto.partitionKey,
|
||||
rowKey: pilotDto.rowKey,
|
||||
id: pilotDto.id,
|
||||
name: pilotDto.name,
|
||||
address: pilotDto.address,
|
||||
city: pilotDto.city,
|
||||
state: pilotDto.state,
|
||||
postalCode: pilotDto.postalCode,
|
||||
email: pilotDto.email,
|
||||
phone: pilotDto.phone,
|
||||
medicalClass: pilotDto.medicalClass,
|
||||
medicalExpiration: pilotDto.medicalExpiration,
|
||||
certificates: JSON.stringify(pilotDto.certificates),
|
||||
endorsements: JSON.stringify(pilotDto.endorsements)
|
||||
}
|
||||
|
||||
return await this.pilotService.update(partitionKey, rowKey, pilot);
|
||||
return await this.pilotService.update(id, pilotDto);
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
|
||||
@@ -113,14 +77,13 @@ export class PilotController {
|
||||
}
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@UseGuards(AuthGuard)
|
||||
@Delete(':partitionKey/:rowKey')
|
||||
async delete(
|
||||
@Param('partitionKey') partitionKey: string,
|
||||
@Param('rowKey') rowKey: string
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
try {
|
||||
return await this.pilotService.delete(partitionKey, rowKey);
|
||||
return await this.pilotService.delete(id);
|
||||
} catch (error) {
|
||||
const customError = error as CustomError;
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { Certificate } from "./certificate/certificate.entity";
|
||||
import { Endorsement } from "./endorsement/endorsement.entity";
|
||||
import { LogEntity } from "src/log/log.entity";
|
||||
|
||||
export class PilotDto {
|
||||
partitionKey: string;
|
||||
rowKey: string;
|
||||
id: string;
|
||||
name: string;
|
||||
address: string;
|
||||
city: string;
|
||||
@@ -12,8 +8,4 @@ export class PilotDto {
|
||||
postalCode: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
medicalClass?: string;
|
||||
medicalExpiration?: string;
|
||||
certificates: Certificate;
|
||||
endorsements: Endorsement
|
||||
}
|
||||
|
||||
@@ -1,18 +1,47 @@
|
||||
import { EntityString } from '@noahspan/azure-database';
|
||||
import { LogEntity } from 'src/log/log.entity';
|
||||
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
|
||||
import { CertificateEntity } from '../certificate/certificate.entity';
|
||||
import { EndorsementEntity } from 'src/endorsement/endorsement.entity';
|
||||
import { MedicalEntity } from 'src/medical/medical.entity';
|
||||
|
||||
export class Pilot {
|
||||
@EntityString() partitionKey: string;
|
||||
@EntityString() rowKey: string;
|
||||
@EntityString() id: string;
|
||||
@EntityString() name: string;
|
||||
@EntityString() address?: string;
|
||||
@EntityString() city?: string;
|
||||
@EntityString() state?: string;
|
||||
@EntityString() postalCode?: string;
|
||||
@EntityString() email?: string;
|
||||
@EntityString() phone?: string;
|
||||
@EntityString() medicalClass?: string;
|
||||
@EntityString() medicalExpiration: string;
|
||||
@EntityString() certificates: string;
|
||||
@EntityString() endorsements: string;
|
||||
@Entity({ name: 'pilots' })
|
||||
export class PilotEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
address: string
|
||||
|
||||
@Column()
|
||||
city: string;
|
||||
|
||||
@Column()
|
||||
state: string;
|
||||
|
||||
@Column()
|
||||
postalCode: string;
|
||||
|
||||
@Column()
|
||||
email: string;
|
||||
|
||||
@Column()
|
||||
phone: string;
|
||||
|
||||
@Column()
|
||||
userId: string | null;
|
||||
|
||||
@OneToMany(() => LogEntity, (log: LogEntity) => log.pilot)
|
||||
logs: LogEntity[];
|
||||
|
||||
@OneToMany(() => CertificateEntity, (certificate: CertificateEntity) => certificate.pilot)
|
||||
certificates: CertificateEntity[];
|
||||
|
||||
@OneToMany(() => EndorsementEntity, (endorsement: EndorsementEntity) => endorsement.pilot)
|
||||
endorsements: EndorsementEntity[];
|
||||
|
||||
@OneToMany(() => MedicalEntity, (medical: MedicalEntity) => medical.pilot)
|
||||
medical: MedicalEntity[];
|
||||
}
|
||||
|
||||
51
api/src/pilot/pilot.interceptor.ts
Normal file
51
api/src/pilot/pilot.interceptor.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import { Observable, map } from 'rxjs';
|
||||
import { CustomJwtPayload } from 'src/interfaces/customJwtPayload.interface';
|
||||
import { PilotEntity } from './pilot.entity';
|
||||
import { IS_PUBLIC_KEY } from '@noahspan/noahspan-modules';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
|
||||
export class PilotInterceptor implements NestInterceptor {
|
||||
constructor(private reflector: Reflector) {}
|
||||
|
||||
intercept(context: ExecutionContext, handler: CallHandler): Observable<any> {
|
||||
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
|
||||
context.getHandler(),
|
||||
context.getClass(),
|
||||
]);
|
||||
|
||||
return handler.handle().pipe(
|
||||
map((data: PilotEntity[]) => {
|
||||
const req = context.switchToHttp().getRequest();
|
||||
const limitData = (data) => {
|
||||
return data.map((pilot: PilotEntity) => {
|
||||
return {
|
||||
id: pilot.id,
|
||||
name: pilot.name
|
||||
};
|
||||
})
|
||||
}
|
||||
console.log(req.headers.authorization)
|
||||
if (req.headers.authorization) {
|
||||
const authHeader = req.headers.authorization;
|
||||
const token = authHeader && authHeader.split(' ')[1];
|
||||
const jwtPayload: CustomJwtPayload = jwtDecode(token);
|
||||
|
||||
if (jwtPayload.roles.includes('Flying.Read')) {
|
||||
const pilots = limitData(data)
|
||||
|
||||
return pilots;
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
} else if (!req.headers.authorization && isPublic) {
|
||||
const publicData = limitData(data);
|
||||
const logs = publicData.slice(0,5)
|
||||
|
||||
return logs;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,15 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { PilotController } from './pilot.controller';
|
||||
import { PilotService } from './pilot.service';
|
||||
import { AzureTableStorageModule } from '@noahspan/azure-database';
|
||||
import { Pilot } from './pilot.entity';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { Log } from 'src/log/log.entity';
|
||||
import { PilotEntity } from './pilot.entity';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
AzureTableStorageModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
useFactory: async (configService: ConfigService) => {
|
||||
return {
|
||||
connectionString: configService.get<string>('azureStorageConnectionString')
|
||||
};
|
||||
},
|
||||
inject: [ConfigService]
|
||||
}),
|
||||
AzureTableStorageModule.forFeature(Log, {
|
||||
createTableIfNotExists: false,
|
||||
table: 'logs'
|
||||
}),
|
||||
AzureTableStorageModule.forRootAsync({
|
||||
imports: [ConfigModule],
|
||||
useFactory: async (configService: ConfigService) => {
|
||||
return {
|
||||
connectionString: configService.get<string>('azureStorageConnectionString')
|
||||
};
|
||||
},
|
||||
inject: [ConfigService]
|
||||
}),
|
||||
AzureTableStorageModule.forFeature(Pilot, {
|
||||
createTableIfNotExists: false,
|
||||
table: 'pilots'
|
||||
})
|
||||
TypeOrmModule.forFeature([PilotEntity])
|
||||
],
|
||||
controllers: [PilotController],
|
||||
exports: [PilotService],
|
||||
providers: [PilotService]
|
||||
})
|
||||
export class PilotModule {}
|
||||
|
||||
@@ -1,54 +1,46 @@
|
||||
import { InjectRepository, Repository } from '@noahspan/azure-database';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Pilot } from './pilot.entity';
|
||||
import { Log } from 'src/log/log.entity';
|
||||
import { LogService } from 'src/log/log.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PilotEntity } from './pilot.entity';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DeleteResult, InsertResult, Repository, UpdateResult } from 'typeorm';
|
||||
import { PilotDto } from './pilot.dto';
|
||||
import { CustomError } from 'src/error/customError';
|
||||
|
||||
@Injectable()
|
||||
export class PilotService {
|
||||
constructor(
|
||||
@InjectRepository(Pilot) private readonly pilotRepository: Repository<Pilot>,
|
||||
@InjectRepository(Log) private readonly logRepository: Repository<Log>
|
||||
@InjectRepository(PilotEntity) private readonly pilotRepository: Repository<PilotEntity>
|
||||
) {}
|
||||
|
||||
async find(partitionKey: string, rowKey: string): Promise<Pilot> {
|
||||
return await this.pilotRepository.find(partitionKey, rowKey);
|
||||
async find(id: string): Promise<PilotEntity> {
|
||||
try {
|
||||
const pilotEntity = await this.pilotRepository.findOneBy({ id });
|
||||
|
||||
if (pilotEntity) {
|
||||
return pilotEntity
|
||||
} else {
|
||||
throw new CustomError('Pilot not found', 'Not found', 404)
|
||||
}
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async findAll(): Promise<Pilot[]> {
|
||||
return await this.pilotRepository.findAll();
|
||||
async findAll(): Promise<PilotEntity[]> {
|
||||
return await this.pilotRepository.find();
|
||||
}
|
||||
|
||||
async create(pilot: Pilot): Promise<Pilot> {
|
||||
// try {
|
||||
// return await this.pilotRepository.create(pilot);
|
||||
// } catch (error) {
|
||||
// throw new Error(error);
|
||||
// }
|
||||
return await this.pilotRepository.create(pilot);
|
||||
async create(pilot: PilotDto): Promise<InsertResult> {
|
||||
return await this.pilotRepository.insert(pilot);
|
||||
}
|
||||
|
||||
async update(
|
||||
partitionKey: string,
|
||||
rowKey: string,
|
||||
pilot: Pilot
|
||||
): Promise<Pilot> {
|
||||
return await this.pilotRepository.update(partitionKey, rowKey, pilot);
|
||||
id: string,
|
||||
pilot: PilotDto
|
||||
): Promise<UpdateResult> {
|
||||
return await this.pilotRepository.update(id, pilot);
|
||||
}
|
||||
|
||||
async delete(partitionKey: string, rowKey: string): Promise<void> {
|
||||
const pilotLogs: Log[] = await this.logRepository.findAll({
|
||||
queryOptions: {
|
||||
filter: `pilotId eq '${rowKey}'`
|
||||
}
|
||||
})
|
||||
|
||||
for (const pilotLog of pilotLogs) {
|
||||
await this.logRepository.delete(pilotLog.partitionKey, pilotLog.rowKey);
|
||||
}
|
||||
|
||||
await this.pilotRepository.delete(partitionKey, rowKey);
|
||||
|
||||
return
|
||||
async delete(id: string): Promise<DeleteResult> {
|
||||
return await this.pilotRepository.delete({ id });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user