Skip to content

Commit

Permalink
Merge branch 'main' into 4247_create_application_versioning_part_3
Browse files Browse the repository at this point in the history
  • Loading branch information
sh16011993 authored Feb 19, 2025
2 parents 0f8665c + 147bbc0 commit d0cb6c9
Show file tree
Hide file tree
Showing 68 changed files with 2,368 additions and 595 deletions.
4 changes: 2 additions & 2 deletions devops/helm/crunchy-postgres/values-0c27fb-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ instances:
storageClassName: netapp-block-standard
requests:
cpu: "2"
memory: 2Gi
memory: 6Gi
limits:
cpu: "4"
memory: 4Gi
memory: 6Gi
replicaCertCopy:
requests:
cpu: 50m
Expand Down
4 changes: 2 additions & 2 deletions devops/openshift/api-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ objects:
failureThreshold: 3
successThreshold: 1
httpGet:
path: /api/
path: /health/
port: "${{PORT}}"
initialDelaySeconds: 40
periodSeconds: 30
Expand All @@ -228,7 +228,7 @@ objects:
failureThreshold: 3
successThreshold: 1
httpGet:
path: /api/
path: /health/
port: "${{PORT}}"
scheme: HTTP
initialDelaySeconds: 10
Expand Down
13 changes: 0 additions & 13 deletions sources/packages/backend/apps/api/src/app.controller.ts

This file was deleted.

13 changes: 9 additions & 4 deletions sources/packages/backend/apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { AppService } from "./app.service";
import { RouterModule } from "@nestjs/core";
import {
Expand All @@ -13,6 +12,7 @@ import {
AuditController,
ConfigController,
DynamicFormController,
HealthController,
} from "./route-controllers";
import { AuthModule } from "./auth/auth.module";
import { AppAESTModule } from "./app.aest.module";
Expand All @@ -31,6 +31,7 @@ import { DatabaseModule } from "@sims/sims-db";
import { NotificationsModule } from "@sims/services/notifications";
import { QueueModule } from "@sims/services/queue";
import { AppExternalModule } from "./app.external.module";
import { AccessLoggerMiddleware } from "./middlewares";

@Module({
imports: [
Expand Down Expand Up @@ -72,7 +73,7 @@ import { AppExternalModule } from "./app.external.module";
]),
],
controllers: [
AppController,
HealthController,
ConfigController,
DynamicFormController,
AuditController,
Expand All @@ -86,4 +87,8 @@ import { AppExternalModule } from "./app.external.module";
ProgramYearService,
],
})
export class AppModule {}
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AccessLoggerMiddleware).exclude("health").forRoutes("*");
}
}
13 changes: 1 addition & 12 deletions sources/packages/backend/apps/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { AppAllExceptionsFilter } from "./app.exception.filter";
import { exit } from "process";
import { setGlobalPipes } from "./utilities/auth-utils";
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
import { Request, Response } from "express";
import { KeycloakConfig } from "@sims/auth/config";
import helmet from "helmet";
import { SystemUsersService } from "@sims/services";
Expand All @@ -29,7 +28,7 @@ async function bootstrap() {
await systemUsersService.loadSystemUser();

// Setting global prefix
app.setGlobalPrefix("api");
app.setGlobalPrefix("api", { exclude: ["health"] });

// Using helmet.
app.use(helmet());
Expand Down Expand Up @@ -58,16 +57,6 @@ async function bootstrap() {
origin: allowAnyOrigin,
});

// Log every request.
app.use((req: Request, _res: Response, next: () => void) => {
logger.log(
`Request - ${req.method} ${req.path} From ${
req.headers.origin ?? "unknown"
} | ${req.headers["user-agent"] ?? "unknown"}`,
);
next();
});

// pipes
setGlobalPipes(app);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Injectable, LoggerService, NestMiddleware } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { InjectLogger } from "@sims/utilities/logger";
import { IUserToken } from "../auth";
import { getClientIPFromRequest } from "../utilities";
import { Request, Response, NextFunction } from "express";

@Injectable()
export class AccessLoggerMiddleware implements NestMiddleware {
constructor(private readonly jwtService: JwtService) {}
/**
* Logs access information of every request.
* @param request http request.
* @param _response http response.
* @param next next function.
*/
use(request: Request, _response: Response, next: NextFunction) {
const { headers, originalUrl, method } = request;
const clientIP = getClientIPFromRequest(request);
const user = this.getUserFromBearerToken(request.headers.authorization);
const userGUID = user ? user.userName : "User GUID not found";
const userAgent = headers["user-agent"] ?? "User agent not found";
const userAccessLog = `Request - ${method} ${originalUrl} From ${clientIP} | User GUID: ${userGUID} | User Agent: ${userAgent}`;
this.logger.log(userAccessLog);
next();
}

/**
* Get decoded user information from bearer token.
* @param bearerToken token to be decoded.
* @returns decoded user information.
*/
private getUserFromBearerToken(bearerToken: string): IUserToken | null {
if (!bearerToken) {
return null;
}
const user = this.jwtService.decode<IUserToken>(
bearerToken.replace("Bearer ", ""),
);
return user;
}

@InjectLogger()
logger: LoggerService;
}
1 change: 1 addition & 0 deletions sources/packages/backend/apps/api/src/middlewares/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./access-logger.middleware";
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import BaseController from "../BaseController";
import { AuditService } from "../../services";
import { Request } from "express";
import { AuditAPIInDTO } from "./models/audit.dto";
import { getClientIPFromRequest } from "../../utilities";

@AllowAuthorizedParty(
AuthorizedParties.institution,
Expand Down Expand Up @@ -37,9 +38,7 @@ export class AuditController extends BaseController {
@UserToken() userToken: IUserToken,
@Req() request: Request,
): void {
const clientIP =
(request.headers["x-forwarded-for"] as string) ||
request.socket.remoteAddress;
const clientIP = getClientIPFromRequest(request);
this.auditService.audit(
clientIP,
userToken.userName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import { Test, TestingModule } from "@nestjs/testing";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { HealthController } from "./health.controller";
import { DatabaseModule } from "@sims/sims-db";

// TODO: must mock DB dependencies.
describe.skip("AppController", () => {
let appController: AppController;
describe.skip("HealthController", () => {
let healthController: HealthController;

beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
imports: [DatabaseModule],
controllers: [AppController],
providers: [AppService],
controllers: [HealthController],
}).compile();

appController = app.get<AppController>(AppController);
healthController = app.get<HealthController>(HealthController);
});

describe("root", () => {
it("should return Hello world string with db connection status and version", () => {
const expected = `Hello World! The database dataSource is true and version: ${
process.env.VERSION ?? "-1"
}`;
expect(appController.getHello()).toBe(expected);
expect(healthController.getHello()).toBe(expected);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Controller, Get } from "@nestjs/common";
import { Public } from "../../auth/decorators";
import { DataSource } from "typeorm";

@Controller("health")
export class HealthController {
constructor(private readonly dataSource: DataSource) {}

/**
* Returns a health check status.
* @returns health check status.
*/
@Get()
@Public()
getHello(): string {
return this.getHeathCheckStatus();
}

/**
* Get health check status.
* @returns health check status.
*/
private getHeathCheckStatus(): string {
try {
return `Hello World! The database dataSource is ${
this.dataSource.isInitialized
} and version: ${process.env.VERSION ?? "-1"}`;
} catch (error: unknown) {
return `Hello world! Fail with error: ${error}`;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,4 @@ export * from "./student/student.external.controller";
export * from "./cas-invoice-batch/cas-invoice-batch.aest.controller";
export * from "./models/primary.identifier.dto";
export * from "./models/common.dto";
export * from "./health-check/health.controller";
Loading

0 comments on commit d0cb6c9

Please sign in to comment.