Skip to content

Commit

Permalink
Merge branch 'main' into feature/#3666-add-base-queue-to-schedulers
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewsignori-aot committed Dec 10, 2024
2 parents bec7724 + 50a9091 commit eaec81f
Show file tree
Hide file tree
Showing 45 changed files with 1,159 additions and 137 deletions.
8 changes: 4 additions & 4 deletions devops/helm/crunchy-postgres/values-0c27fb-prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ instances:
storage: 5Gi
storageClassName: netapp-block-standard
requests:
cpu: 250m
memory: 512Mi
cpu: "2"
memory: 2Gi
limits:
cpu: "1"
memory: 1Gi
cpu: "4"
memory: 4Gi
replicaCertCopy:
requests:
cpu: 50m
Expand Down
38 changes: 38 additions & 0 deletions devops/openshift/api-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,38 @@ objects:
to:
kind: Service
name: ${NAME}
- apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: ${EXTERNAL_SWAGGER_NAME}-route
annotations:
haproxy.router.openshift.io/balance: leastconn
haproxy.router.openshift.io/disable_cookies: "true"
haproxy.router.openshift.io/hsts_header: max-age=31536000;includeSubDomains;preload
haproxy.router.openshift.io/timeout: 30s
spec:
host: ${HOST_NAME}
path: ${EXTERNAL_SWAGGER_PATH}
port:
targetPort: http
tls:
insecureEdgeTerminationPolicy: Redirect
termination: edge
certificate: |
-----BEGIN CERTIFICATE-----
${TLS_CERTIFICATE}
-----END CERTIFICATE-----
key: |
-----BEGIN PRIVATE KEY-----
${TLS_KEY}
-----END PRIVATE KEY-----
caCertificate: |
-----BEGIN CERTIFICATE-----
${TLS_CA_CERTIFICATE}
-----END CERTIFICATE-----
to:
kind: Service
name: ${NAME}
- apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
Expand Down Expand Up @@ -345,6 +377,12 @@ parameters:
- name: SWAGGER_PATH
value: /swagger
required: true
- name: EXTERNAL_SWAGGER_NAME
value: external-swagger
required: true
- name: EXTERNAL_SWAGGER_PATH
value: /external/swagger
required: true
- name: PROJECT
value: sims
- name: SERVICE_NAME
Expand Down
21 changes: 21 additions & 0 deletions sources/packages/backend/apps/api/src/app.external.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Module } from "@nestjs/common";
import { StudentExternalController } from "./route-controllers";
import { AuthModule } from "./auth/auth.module";
import { StudentService } from "./services";
import {
DisbursementOverawardService,
NoteSharedService,
SFASIndividualService,
} from "@sims/services";

@Module({
imports: [AuthModule],
controllers: [StudentExternalController],
providers: [
StudentService,
SFASIndividualService,
DisbursementOverawardService,
NoteSharedService,
],
})
export class AppExternalModule {}
6 changes: 6 additions & 0 deletions sources/packages/backend/apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { ConfigModule } from "@sims/utilities/config";
import { DatabaseModule } from "@sims/sims-db";
import { NotificationsModule } from "@sims/services/notifications";
import { QueueModule } from "@sims/services/queue";
import { AppExternalModule } from "./app.external.module";

@Module({
imports: [
Expand All @@ -43,6 +44,7 @@ import { QueueModule } from "@sims/services/queue";
AppAESTModule,
AppInstitutionsModule,
AppStudentsModule,
AppExternalModule,
AppSupportingUsersModule,
QueueModule,
ClamAntivirusModule,
Expand All @@ -63,6 +65,10 @@ import { QueueModule } from "@sims/services/queue";
path: ClientTypeBaseRoute.SupportingUser,
module: AppSupportingUsersModule,
},
{
path: ClientTypeBaseRoute.External,
module: AppExternalModule,
},
]),
],
controllers: [
Expand Down
17 changes: 17 additions & 0 deletions sources/packages/backend/apps/api/src/auth/audiences.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Audiences recognized by the API.
* This is present on aud token claim.
*/
export enum Audiences {
/**
* Audience for the SIMS API.
* Every user token must have this audience to be considered valid.
*/
SIMSApi = "sims-api",

/**
* Audience for the SIMS API External.
* External access user token must have this additional audience to be considered valid.
*/
SIMSApiExternal = "sims-api-external",
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export enum AuthorizedParties {
student = "student",
aest = "aest",
supportingUsers = "supporting-users",
external = "external",
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { IdentityProviders } from "@sims/sims-db";
import { ConfigService } from "@sims/utilities/config";
import { ApiProcessError } from "../../types";
import { INVALID_BETA_USER } from "../../constants";
import { Audiences } from "../../auth/audiences.enum";

/**
* Inspect the token to check if the correct authorized party
Expand Down Expand Up @@ -42,7 +43,13 @@ export class AuthorizedPartiesGuard implements CanActivate {
"Client is not authorized under the expected authorized party(azp).",
);
}

if (
userToken.azp === AuthorizedParties.external &&
Array.isArray(userToken.aud) &&
userToken.aud.includes(Audiences.SIMSApiExternal)
) {
return true;
}
const isAllowedIDP = this.isAllowedIDP(
userToken.azp,
userToken.identityProvider,
Expand Down
3 changes: 2 additions & 1 deletion sources/packages/backend/apps/api/src/auth/jwt.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { KeycloakConfig } from "@sims/auth/config";
import { ConfigService } from "@sims/utilities/config";
import { INVALID_BETA_USER } from "../constants";
import { ApiProcessError } from "../types";
import { Audiences } from "./audiences.enum";

/**
* Inspect the header looking for the authentication header,
Expand All @@ -31,7 +32,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: KeycloakConfig.PEM_PublicKey,
audience: "sims-api",
audience: Audiences.SIMSApi,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ export interface IUserToken {
* Authorized party, Keycloak client used for the authentication.
*/
azp: AuthorizedParties;
/**
* Audience, Keycloak audience used for the authentication.
*/
aud: string | string[];
/**
* When the user is authenticated using the bceidboth IDP and the user has a business BCeID account,
* this property contains the guid that identifies his business.
Expand Down
10 changes: 8 additions & 2 deletions sources/packages/backend/apps/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Request, Response } from "express";
import { KeycloakConfig } from "@sims/auth/config";
import helmet from "helmet";
import { SystemUsersService } from "@sims/services";
import { AppExternalModule } from "./app.external.module";

async function bootstrap() {
await KeycloakConfig.load();
Expand Down Expand Up @@ -73,8 +74,7 @@ async function bootstrap() {
// Configure Swagger.
if (process.env.SWAGGER_ENABLED?.toLowerCase() === "true") {
const options = new DocumentBuilder()
.setTitle(process.env.PROJECT_NAME)
.setDescription(`The ${process.env.PROJECT_NAME} API description`)
.setTitle("StudentAid BC")
.setVersion("1.0.0")
.addBearerAuth(
{
Expand All @@ -87,6 +87,12 @@ async function bootstrap() {
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup("swagger", app, document);

// External swagger
const externalDocument = SwaggerModule.createDocument(app, options, {
include: [AppExternalModule], // Includes only AppExternalModule.
});
SwaggerModule.setup("external/swagger", app, externalDocument);
}

// Starting application
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,23 @@ describe("CASSupplierAESTController(e2e)-getCASSuppliers", () => {
db = createE2EDataSources(dataSource);
});

it("Should get all the CAS suppliers for a student when CAS suppliers info is requested for a student.", async () => {
it("Should get all the CAS suppliers with and without error for a student when CAS suppliers info is requested for a student.", async () => {
// Arrange
const savedCASSupplier1 = await saveFakeCASSupplier(db);
const student = savedCASSupplier1.student;
const savedCASSupplier2 = await saveFakeCASSupplier(
db,
{ student },
{ initialValues: { supplierStatus: SupplierStatus.VerifiedManually } },
{
initialValues: {
supplierStatus: SupplierStatus.ManualIntervention,
status: "ACTIVE",
errors: [
"[0034] SIN is already in use.",
"[9999] Duplicate Supplier , Reason: [0065]- Possible duplicate exists, please use online form",
],
},
},
);

const endpoint = `/aest/cas-supplier/student/${student.id}`;
Expand All @@ -44,16 +53,24 @@ describe("CASSupplierAESTController(e2e)-getCASSuppliers", () => {
.expect({
items: [
{
id: savedCASSupplier2.id,
dateCreated: savedCASSupplier2.createdAt.toISOString(),
status: savedCASSupplier2.status,
supplierNumber: savedCASSupplier2.supplierNumber,
supplierProtected: null,
supplierProtected: true,
supplierStatus: savedCASSupplier2.supplierStatus,
isValid: savedCASSupplier2.isValid,
supplierSiteCode:
savedCASSupplier2.supplierAddress.supplierSiteCode,
siteStatus: savedCASSupplier2.supplierAddress.status,
addressLine1: savedCASSupplier2.supplierAddress.addressLine1,
siteProtected: savedCASSupplier2.supplierAddress.siteProtected,
errors: savedCASSupplier2.errors,
},
{
id: savedCASSupplier1.id,
dateCreated: savedCASSupplier1.createdAt.toISOString(),
status: savedCASSupplier1.status,
supplierNumber: savedCASSupplier1.supplierNumber,
supplierProtected: savedCASSupplier1.supplierProtected,
supplierStatus: savedCASSupplier1.supplierStatus,
Expand All @@ -63,6 +80,7 @@ describe("CASSupplierAESTController(e2e)-getCASSuppliers", () => {
siteStatus: savedCASSupplier1.supplierAddress.status,
addressLine1: savedCASSupplier1.supplierAddress.addressLine1,
siteProtected: savedCASSupplier1.supplierAddress.siteProtected,
errors: null,
},
],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ export class CASSupplierAESTController extends BaseController {
studentId,
);
const casSupplierInfoDTOList = casSuppliers.map((casSupplier) => ({
id: casSupplier.id,
dateCreated: casSupplier.createdAt,
status: casSupplier.status,
supplierNumber: casSupplier.supplierNumber,
supplierProtected: casSupplier.supplierProtected,
supplierStatus: casSupplier.supplierStatus,
Expand All @@ -70,6 +72,7 @@ export class CASSupplierAESTController extends BaseController {
addressLine1: casSupplier.supplierAddress?.addressLine1,
siteStatus: casSupplier.supplierAddress?.status,
siteProtected: casSupplier.supplierAddress?.siteProtected,
errors: casSupplier?.errors,
}));
return { items: casSupplierInfoDTOList };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export class CASSupplierInfoAPIOutDTO {
}

export class CASSupplierInfoItemAPIOutDTO {
id: number;
dateCreated: Date;
status: string;
supplierNumber?: string;
supplierProtected?: boolean;
supplierStatus: SupplierStatus;
Expand All @@ -15,6 +17,7 @@ export class CASSupplierInfoItemAPIOutDTO {
addressLine1?: string;
siteStatus?: CASSupplierSiteStatus;
siteProtected?: string;
errors?: string[];
}

export class AddCASSupplierAPIInDTO {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@ export * from "./program-year/program-year.controller.service";
export * from "./cas-supplier/cas-supplier.aest.controller";
export * from "./application-restriction-bypass/application-restriction-bypass.aest.controller";
export * from "./audit/audit.controller";
export * from "./student/student.external.controller";
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,23 @@ export class UpdateStudentDetailsAPIInDTO {
@MaxLength(NOTE_DESCRIPTION_MAX_LENGTH)
noteDescription: string;
}

/**
* Student details.
*/
export class StudentDetailsAPIOutDTO {
firstName: string;
lastName: string;
sin: string;
dateOfBirth: string;
address: AddressAPIOutDTO;
applicationNumbers: string[];
}

/**
* Student external search parameters.
*/
export class ExternalSearchStudentAPIInDTO {
@IsValidSIN()
sin: string;
}
Loading

0 comments on commit eaec81f

Please sign in to comment.