refactoring

This commit is contained in:
2025-01-31 09:27:31 -06:00
parent 986d23b2f6
commit a12985922f
31 changed files with 12142 additions and 17099 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1 +1,6 @@
node_modules
node_modules
.git
.gitignore
*.md
infrastructure
test

3
.gitignore vendored
View File

@@ -4,4 +4,5 @@ node_modules
**/.env.*
.DS_Store
.dapr
**/**/secrets.json
**/**/secrets.json
.prod

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
inject-workspace-packages=true

View File

@@ -1,18 +1,39 @@
FROM --platform=linux/amd64 node:18-alpine AS base
# FROM --platform=linux/amd64 node:18-alpine AS base
# ENV PNPM_HOME="/pnpm"
# ENV PATH="$PNPM_HOME:$PATH"
# RUN corepack enable
# FROM base AS api
# COPY /api/dist /app/dist
# COPY /api/node_modules /app/node_modules
# WORKDIR /app
# EXPOSE 3000
# # CMD ["node", "dist/main.js"]
# ENTRYPOINT ["tail", "-f", "/dev/null"]
# FROM base AS app
# COPY /app/dist /app/dist
# WORKDIR /app
# RUN npm i -g serve
# EXPOSE 8080
# CMD [ "serve", "-s", "/dist", "-p", "8080" ]
FROM node:18-slim AS base
FROM base AS api
COPY ./api/dist ./api/dist
COPY ./api/node_modules ./api/node_modules
WORKDIR api
COPY ./.prod/api .
EXPOSE 3000
CMD ["node", "/api/dist/main.js"]
CMD ["node", "dist/main.js"]
# ENTRYPOINT ["tail", "-f", "/dev/null"]
FROM base AS app
WORKDIR /app
COPY ./.prod/app .
RUN npm i -g serve
# WORKDIR ./app
COPY ./app/dist ./app/dist
# COPY ./app .
# RUN npm install
EXPOSE 8080
CMD [ "serve", "-s", "app/dist", "-p", "8080" ]
# CMD ["npm", "run", "dev"]
# ENTRYPOINT ["tail", "-f", "/dev/null"]
CMD [ "serve", "-s", "dist", "-p", "8080" ]

8766
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -30,10 +30,10 @@
"@nestjs/core": "^10.0.0",
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@noahspan/azure-database": "^3.1.0",
"@noahspan/noahspan-modules": "^0.5.2",
"@noahspan/azure-database": "^3.1.2",
"@schematics/angular": "^17.3.7",
"dotenv": "^16.4.7",
"express-jwt": "^8.5.1",
"passport-azure-ad": "^4.3.5",
"reflect-metadata": "0.1.13",
"rxjs": "^7.8.1",
@@ -57,6 +57,9 @@
"tsconfig-paths": "^4.2.0",
"typescript": "^5.1.3"
},
"files": [
"dist"
],
"jest": {
"moduleFileExtensions": [
"js",

View File

@@ -3,14 +3,17 @@ import {
Get,
Headers,
Query,
StreamableFile
StreamableFile,
UseGuards
} from '@nestjs/common';
import { Client as MsGraphClient } from '@microsoft/microsoft-graph-client';
import { MsGraphService, Public } from '@noahspan/noahspan-modules';
import { MsGraphService } from './msGraph/ms-graph.service'
import { Person } from '@microsoft/microsoft-graph-types';
import { AppService } from './app.service';
import { AuthGuard } from '@nestjs/passport';
@Controller()
@UseGuards(AuthGuard('azure-ad'))
export class AppController {
constructor(
private readonly appService: AppService,
@@ -72,7 +75,6 @@ export class AppController {
}
}
@Public()
@Get('hello')
async getHello(): Promise<string> {
return this.appService.getHello();

View File

@@ -1,9 +1,8 @@
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthGuard, AuthModule } from '@noahspan/noahspan-modules';
import { MsGraphModule } from '@noahspan/noahspan-modules';
import { APP_GUARD } from '@nestjs/core';
import { AuthModule } from './auth/auth.module';
import { MsGraphModule } from './msGraph/ms-graph.module';
import { FeatureFlagModule } from './featureFlag/feature-flag.module'
import { LogModule } from './log/log.module';
import { PilotModule } from './pilot/pilot.module';
@@ -45,10 +44,6 @@ import configuration from './config/configuration';
],
controllers: [AppController],
providers: [
{
provide: APP_GUARD,
useClass: AuthGuard
},
{
provide: APP_FILTER,
useClass: HttpExceptionFilter

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
// import { MsGraphService, MsGraphClient } from '@noahspan/noahspan-modules';
import { Client as MsGraphClient } from '@microsoft/microsoft-graph-client';
import { MsGraphService } from '@noahspan/noahspan-modules';
import { MsGraphService } from './msGraph/ms-graph.service';
@Injectable()
export class AppService {

View File

@@ -0,0 +1,5 @@
export interface AuthModuleOptions {
tenantId: string;
clientId: string;
clientSecret: string;
}

View File

@@ -0,0 +1,4 @@
import { ConfigurableModuleBuilder } from '@nestjs/common';
import { AuthModuleOptions } from './auth.interface';
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder<AuthModuleOptions>().build()

View File

@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { AzureAdStrategy } from './auth.strategy';
import { ConfigurableModuleClass } from './auth.module-definition';
@Module({
imports: [
PassportModule.register({
defaultStrategy: 'azure-ad'
})
],
providers: [AzureAdStrategy]
})
export class AuthModule extends ConfigurableModuleClass {}

View File

@@ -0,0 +1,26 @@
import { Inject, Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { AuthModuleOptions } from './auth.interface'
import { MODULE_OPTIONS_TOKEN } from "./auth.module-definition";
import { BearerStrategy } from 'passport-azure-ad'
@Injectable()
export class AzureAdStrategy extends PassportStrategy(
BearerStrategy,
'azure-ad'
) {
constructor(@Inject(MODULE_OPTIONS_TOKEN) authModuleOptions: AuthModuleOptions) {
console.log(authModuleOptions)
super({
identityMetadata: `https://login.microsoftonline.com/${authModuleOptions.tenantId}/.well-known/openid-configuration`,
clientID: authModuleOptions.clientId,
audience: `api://${authModuleOptions.clientId}`,
loggingLevel: 'info',
loggingNoPII: false
})
}
async validate(data: any): Promise<any> {
return data;
}
}

View File

@@ -0,0 +1,9 @@
export class CustomError extends Error {
statusCode: number;
constructor(message, name, statusCode) {
super(message);
this.name = name;
this.statusCode = statusCode;
}
}

View File

@@ -3,16 +3,18 @@ import {
Get,
HttpException,
Param,
UseGuards,
} from '@nestjs/common';
import { FeatureFlagService } from './feature-flag.service';
import { CustomError, Public } from '@noahspan/noahspan-modules';
import { CustomError } from '../error/customError';
import { AuthGuard } from '@nestjs/passport';
@Controller('featureFlags')
@UseGuards(AuthGuard('azure-ad'))
export class FeatureFlagController {
constructor(private readonly featureFlagService: FeatureFlagService) {}
@Get(':partitionKey/:rowKey')
@Public()
async find(
@Param('partitionKey') partitionKey: string,
@Param('rowKey') rowKey: string
@@ -27,7 +29,6 @@ export class FeatureFlagController {
}
@Get()
@Public()
async findAll() {
try {
return await this.featureFlagService.findAll();

View File

@@ -6,14 +6,18 @@ import {
HttpException,
Param,
Post,
Put
Put,
UseGuards
} from '@nestjs/common';
import { LogDto } from './log.dto';
import { Log } from './log.entity';
import { LogService } from './log.service';
import { CustomError } from '@noahspan/noahspan-modules';
import { CustomError } from '../error/customError';
import { AuthGuard } from '@nestjs/passport';
@Controller('logs')
@UseGuards(AuthGuard('azure-ad'))
export class LogController {
constructor(private readonly logService: LogService) {}
@@ -31,6 +35,7 @@ export class LogController {
}
}
// @Public()
@Get()
async findAll(): Promise<Log[]> {
try {

View File

@@ -3,13 +3,16 @@ import { AppModule } from './app.module';
import { HttpService } from '@nestjs/axios';
import { HttpExceptionFilter } from './filters/http-exception.filter';
import { InternalServerErrorException } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
async function bootstrap() {
const httpService = new HttpService();
const app = await NestFactory.create(AppModule);
app.enableCors();
app.setGlobalPrefix('api');
app.useGlobalFilters(new HttpExceptionFilter());
httpService.axiosRef.interceptors.response.use(
(response) => {
return response;
@@ -20,7 +23,7 @@ async function bootstrap() {
throw new InternalServerErrorException();
}
);
app.enableCors();
await app.listen(3000);
}

View File

@@ -0,0 +1,5 @@
export interface MsGraphModuleOptions {
tenantId: string;
clientId: string;
clientSecret: string;
}

View File

@@ -0,0 +1,4 @@
import { ConfigurableModuleBuilder } from '@nestjs/common';
import { MsGraphModuleOptions } from './ms-graph.interface';
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder<MsGraphModuleOptions>().build()

View File

@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { MsGraphService } from './ms-graph.service';
import { ConfigurableModuleClass } from './ms-graph.module-definition';
@Module({
providers: [MsGraphService],
exports: [MsGraphService]
})
export class MsGraphModule extends ConfigurableModuleClass {}

View File

@@ -0,0 +1,41 @@
import { Inject, Injectable } from '@nestjs/common';
import { MsGraphModuleOptions } from './ms-graph.interface';
import { Client } from '@microsoft/microsoft-graph-client';
import { AuthenticationResult, ConfidentialClientApplication, OnBehalfOfRequest } from '@azure/msal-node';
import { MODULE_OPTIONS_TOKEN } from './ms-graph.module-definition';
@Injectable()
export class MsGraphService {
constructor(@Inject(MODULE_OPTIONS_TOKEN) private msGraphModuleOptions: MsGraphModuleOptions) {}
async getMsGraphAuth(accessToken: string, scopes: string[]): Promise<string> {
try {
const oboRequest: OnBehalfOfRequest = {
oboAssertion: accessToken,
scopes: scopes
}
const cca = new ConfidentialClientApplication({
auth: {
clientId: this.msGraphModuleOptions.clientId,
clientSecret: this.msGraphModuleOptions.clientSecret,
authority: `https://login.microsoftonline.com/${this.msGraphModuleOptions.tenantId}`
}
});
const authenticationResult: AuthenticationResult = await cca.acquireTokenOnBehalfOf(oboRequest);
return authenticationResult.accessToken
} catch (error) {
return error
}
}
async getMsGraphClientDelegated(accessToken): Promise<Client> {
const client = await Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
return client;
}
}

View File

@@ -7,21 +7,20 @@ import {
Param,
Post,
Put,
UseInterceptors
UseGuards,
} from '@nestjs/common';
import { PilotDto } from './pilot.dto';
import { Pilot } from './pilot.entity';
import { PilotService } from './pilot.service';
import { CustomError, Public } from '@noahspan/noahspan-modules';
import { PilotInterceptor } from './interceptors/pilot.interceptor';
import { CustomError } from '../error/customError';
import { AuthGuard } from '@nestjs/passport'
@Controller('pilots')
@UseGuards(AuthGuard('azure-ad'))
export class PilotController {
constructor(private readonly pilotService: PilotService) {}
@Get(':partitionKey/:rowKey')
@Public()
@UseInterceptors(PilotInterceptor)
async find(
@Param('partitionKey') partitionKey: string,
@Param('rowKey') rowKey: string
@@ -36,8 +35,6 @@ export class PilotController {
}
@Get()
@Public()
@UseInterceptors(PilotInterceptor)
async findAll() {
try {
return await this.pilotService.findAll();

8237
app/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -31,5 +31,8 @@
},
"engines": {
"node": ">=18.0.0"
}
},
"files": [
"dist"
]
}

View File

@@ -137,35 +137,35 @@ const SiteNav: React.FC<unknown> = () => {
// };
// }, []);
// useEffect(() => {
// const setUserProfile = async () => {
// try {
// setLoading(true);
useEffect(() => {
const setUserProfile = async () => {
try {
setLoading(true);
// const accessToken: string = await getAccessToken();
// const userProfile = await getUserProfile(accessToken);
// const userPhoto = await getUserPhoto(accessToken);
const accessToken: string = await getAccessToken();
const userProfile = await getUserProfile(accessToken);
const userPhoto = await getUserPhoto(accessToken);
// setUserPhoto(userPhoto);
setUserPhoto(userPhoto);
// appContext.dispatch({
// type: 'SET_USER_PROFILE',
// payload: userProfile
// });
// } catch (error) {
// console.log(error);
// } finally {
// setLoading(false);
// }
// };
appContext.dispatch({
type: 'SET_USER_PROFILE',
payload: userProfile
});
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
};
// if (
// isAuthenticated &&
// Object.keys(appContext.state.userProfile).length === 0
// ) {
// setUserProfile();
// }
// }, [isAuthenticated]);
if (
isAuthenticated &&
Object.keys(appContext.state.userProfile).length === 0
) {
setUserProfile();
}
}, [isAuthenticated]);
return (
<Navbar

View File

@@ -10,28 +10,29 @@ import { MsalProvider } from '@azure/msal-react';
import { msalConfig } from './auth/msalConfig';
const msalInstance: PublicClientApplication = new PublicClientApplication(msalConfig);
const accounts = msalInstance.getAllAccounts();
console.log({ accounts, msalInstance });
msalInstance.initialize().then(() => {
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
msalInstance.setActiveAccount(accounts[0]);
}
msalInstance.addEventCallback((event: EventMessage) => {
if (event.eventType === EventType.LOGIN_SUCCESS && event.payload) {
const payload = event.payload as AuthenticationResult;
const account = payload.account;
msalInstance.setActiveAccount(account);
if (accounts.length > 0) {
msalInstance.setActiveAccount(accounts[0]);
}
});
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
{/* <AppContextProvider> */}
<BrowserRouter>
<App pca={msalInstance} />
</BrowserRouter>
{/* </AppContextProvider> */}
</React.StrictMode>
);
msalInstance.addEventCallback((event: EventMessage) => {
if (event.eventType === EventType.LOGIN_SUCCESS && event.payload) {
const payload = event.payload as AuthenticationResult;
const account = payload.account;
msalInstance.setActiveAccount(account);
}
});
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<AppContextProvider>
<BrowserRouter>
<App pca={msalInstance} />
</BrowserRouter>
</AppContextProvider>
</React.StrictMode>
);
})

View File

@@ -11,17 +11,23 @@ services:
command: 'azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose'
api:
container_name: api
container_name: flying-api
build:
context: ./api
dockerfile: Dockerfile
context: .
target: api
ports:
- '7071:3000'
- '3000:3000'
env_file:
- ./api/.env
# swa:
# image: swacli/static-web-apps-cli
# ports:
# - "4280:4280"
# command: "swa start "
app:
container_name: flying-app
build:
context: .
target: app
ports:
- '8080:8080'
# env_file:
# - ./app/.env

View File

@@ -5,7 +5,9 @@
"start": "concurrently 'npm run start:azure -w api' 'wait-on tcp:0.0.0.0:7071 && npm run dev -w app'",
"format": "prettier --write \"**/src/**/*.ts\" \"**/test/**/*.ts\"",
"lint": "npm run lint -w api && npm run lint -w app",
"prepare": "husky || true"
"prepare": "husky || true",
"preprod": "rimraf ./.prod && pnpm --filter api build && pnpm --filter app build",
"prod": "pnpm --filter api --prod deploy ./.prod/api && pnpm --filter app --prod deploy ./.prod/app"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -18,6 +20,7 @@
"husky": "^9.0.11",
"lint-staged": "^15.2.2",
"prettier": "3.2.5",
"rimraf": "^6.0.1",
"wait-on": "^7.2.0"
},
"lint-staged": {

11879
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

3
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,3 @@
packages:
- 'api'
- 'app'