Skip to content

Commit

Permalink
feat: Release/lewis moon snail (#648)
Browse files Browse the repository at this point in the history
Co-authored-by: dmitri-korin-bcps <[email protected]>
Co-authored-by: Barrett Falk <[email protected]>
Co-authored-by: gregorylavery <[email protected]>
Co-authored-by: Scarlett <[email protected]>
Co-authored-by: Mike <[email protected]>
Co-authored-by: Mike Sears <[email protected]>
Co-authored-by: jeznorth <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Scarlett <[email protected]>
  • Loading branch information
10 people authored Sep 19, 2024
1 parent 33f7f58 commit a2671b4
Show file tree
Hide file tree
Showing 202 changed files with 11,457 additions and 2,518 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pr-open.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
package: [backend, frontend, migrations, webeoc]
timeout-minutes: 10
steps:
- uses: bcgov-nr/action-builder-ghcr@v2.0.2
- uses: bcgov-nr/action-builder-ghcr@v2.2.0
with:
keep_versions: 50
package: ${{ matrix.package }}
Expand Down
10 changes: 10 additions & 0 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ import { GirTypeCodeModule } from "./v1/gir_type_code/gir_type_code.module";
import { GeneralIncidentComplaintModule } from "./v1/gir_complaint/gir_complaint.module";
import { FeatureFlagModule } from "./v1/feature_flag/feature_flag.module";
import { FeatureCodeModule } from "./v1/feature_code/feature_code.module";
import { TeamModule } from "./v1/team/team.module";
import { TeamCodeModule } from "./v1/team_code/team_code.module";
import { OfficerTeamXrefModule } from "./v1/officer_team_xref/officer_team_xref.module";
import { ComplaintMethodReceivedCodeModule } from "./v1/complaint_method_received_code/complaint_method_received_code.module";
import { CompMthdRecvCdAgcyCdXrefModule } from "./v1/comp_mthd_recv_cd_agcy_cd_xref/comp_mthd_recv_cd_agcy_cd_xref.module";

console.log("Var check - POSTGRESQL_HOST", process.env.POSTGRESQL_HOST);
console.log("Var check - POSTGRESQL_DATABASE", process.env.POSTGRESQL_DATABASE);
Expand Down Expand Up @@ -118,6 +123,11 @@ if (process.env.POSTGRESQL_PASSWORD != null) {
GeneralIncidentComplaintModule,
FeatureFlagModule,
FeatureCodeModule,
TeamModule,
TeamCodeModule,
OfficerTeamXrefModule,
ComplaintMethodReceivedCodeModule,
CompMthdRecvCdAgcyCdXrefModule,
],
controllers: [AppController],
providers: [AppService, ComplaintSequenceResetScheduler],
Expand Down
5 changes: 5 additions & 0 deletions backend/src/common/has-role.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const hasRole = (req, role: string) => {
const userroles = req.user.client_roles;
const hasRole = userroles?.includes(role);
return hasRole;
};
5 changes: 4 additions & 1 deletion backend/src/enum/role.enum.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export enum Role {
COS_OFFICER = "COS Officer",
COS_ADMIN = "COS Admin",
COS_ADMINISTRATOR = "COS Administrator",
CEEB = "CEEB",
CEEB_COMPLIANCE_COORDINATOR = "CEEB Compliance Coordinator",
CEEB_SECTION_HEAD = "CEEB Section Head",
TEMPORARY_TEST_ADMIN = "TEMPORARY_TEST_ADMIN",
READ_ONLY = "READ ONLY",
}
10 changes: 10 additions & 0 deletions backend/src/external_api/css/css.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from "@nestjs/common";
import { CssService } from "./css.service";
import { ConfigurationModule } from "../../v1/configuration/configuration.module";

@Module({
imports: [ConfigurationModule],
providers: [CssService],
exports: [CssService],
})
export class CssModule {}
28 changes: 28 additions & 0 deletions backend/src/external_api/css/css.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Test, TestingModule } from "@nestjs/testing";
import { getRepositoryToken } from "@nestjs/typeorm";
import { ConfigurationService } from "../../v1/configuration/configuration.service";
import { Configuration } from "../../v1/configuration/entities/configuration.entity";
import { CssService } from "./css.service";

describe("CssService", () => {
let service: CssService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
CssService,
ConfigurationService,
{
provide: getRepositoryToken(Configuration),
useValue: {},
},
],
}).compile();

service = module.get<CssService>(CssService);
});

it("should be defined", () => {
expect(service).toBeDefined();
});
});
177 changes: 177 additions & 0 deletions backend/src/external_api/css/css.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { Inject, Injectable, Logger } from "@nestjs/common";
import { ExternalApiService } from "../external-api-service";
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
import { get } from "../../helpers/axios-api";
import { ConfigurationService } from "../../v1/configuration/configuration.service";

@Injectable()
export class CssService implements ExternalApiService {
private readonly logger = new Logger(CssService.name);

readonly authApi: string;
readonly baseUri: string;
readonly clientId: string;
readonly clientSecret: string;
readonly grantType: string;
readonly env: string;

@Inject(ConfigurationService)
readonly configService: ConfigurationService;

constructor() {
this.authApi = process.env.CSS_TOKEN_URL;
this.baseUri = process.env.CSS_URL;
this.clientId = process.env.CSS_CLIENT_ID;
this.clientSecret = process.env.CSS_CLIENT_SECRET;
this.grantType = "client_credentials";
this.env = process.env.ENVIRONMENT;
}

authenticate = async (): Promise<string> => {
const response: AxiosResponse = await axios.post(
this.authApi,
{
client_id: this.clientId,
client_secret: this.clientSecret,
grant_type: this.grantType,
},
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
},
);
return response?.data?.access_token;
};

getUserIdirByName = async (firstName, lastName): Promise<AxiosResponse> => {
try {
const apiToken = await this.authenticate();
const url = `${this.baseUri}/api/v1/${this.env}/idir/users?firstName=${firstName}&lastName=${lastName}`;
const config: AxiosRequestConfig = {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiToken}`,
},
};
const response = await get(apiToken, url, config);
return response?.data.data;
} catch (error) {
this.logger.error(`exception: unable to get user: ${firstName} ${lastName} - error: ${error}`);
throw new Error(`exception: unable to get user: ${firstName} ${lastName} - error: ${error}`);
}
};

getUserRoles = async (userIdir): Promise<{ name: string; composite: string }[]> => {
try {
const apiToken = await this.authenticate();
const url = `${this.baseUri}/api/v1/integrations/4794/${this.env}/users/${userIdir}/roles`;
const config: AxiosRequestConfig = {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiToken}`,
},
};
const response = await get(apiToken, url, config);
return response?.data.data;
} catch (error) {
this.logger.error(`exception: unable to get user's roles ${userIdir} - error: ${error}`);
throw new Error(`exception: unable to get user's roles ${userIdir} - error: ${error}`);
}
};

updateUserRole = async (userIdir, userRoles): Promise<{ name: string; composite: string }[]> => {
try {
const apiToken = await this.authenticate();
const url = `${this.baseUri}/api/v1/integrations/4794/${this.env}/users/${userIdir}/roles`;
const config: AxiosRequestConfig = {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiToken}`,
},
};
const response = await axios.post(url, userRoles, config);
return response?.data.data;
} catch (error) {
this.logger.error(`exception: unable to update user's roles ${userIdir} - error: ${error}`);
throw new Error(`exception: unable to update user's roles ${userIdir} - error: ${error}`);
}
};

deleteUserRole = async (userIdir, roleName): Promise<AxiosResponse> => {
try {
const apiToken = await this.authenticate();
const url = `${this.baseUri}/api/v1/integrations/4794/${this.env}/users/${userIdir}/roles/${roleName}`;
const config: AxiosRequestConfig = {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiToken}`,
},
};
const response = await axios.delete(url, config);
return response?.data.data;
} catch (error) {
this.logger.error(`exception: unable to delete user's role ${userIdir} - error: ${error}`);
throw new Error(`exception: unable to delete user's role ${userIdir} - error: ${error}`);
}
};

getUserRoleMapping = async (): Promise<AxiosResponse> => {
try {
const apiToken = await this.authenticate();
//Get all roles from NatCom CSS integation
const rolesUrl = `${this.baseUri}/api/v1/integrations/4794/${this.env}/roles`;
const config: AxiosRequestConfig = {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiToken}`,
},
};
const roleRes = await get(apiToken, rolesUrl, config);
if (roleRes?.data.data.length > 0) {
const {
data: { data: roleList },
} = roleRes;

//Get all users for each role
let usersUrl: string = "";
const usersRoles = await Promise.all(
roleList.map(async (role) => {
usersUrl = `${this.baseUri}/api/v1/integrations/4794/${this.env}/roles/${role.name}/users`;
const userRes = await get(apiToken, encodeURI(usersUrl), config);
if (userRes?.data.data.length > 0) {
const {
data: { data: users },
} = userRes;
let usersRolesTemp = await Promise.all(
users.map((user) => {
return {
userId: user.username
.replace(/@idir$/i, "")
.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, "$1-$2-$3-$4-$5"),
role: role.name,
};
}),
);
return usersRolesTemp;
}
}),
);

//exclude empty roles and concatenate all sub-array elements
const usersRolesFlat = usersRoles.filter((item) => item !== undefined).flat();

//group the array elements by a user id
const usersRolesGroupped = usersRolesFlat.reduce((grouping, item) => {
grouping[item.userId] = [...(grouping[item.userId] || []), item.role];
return grouping;
}, {});

return usersRolesGroupped;
}
} catch (error) {
this.logger.error(`exception: error: ${error}`);
return;
}
};
}
7 changes: 7 additions & 0 deletions backend/src/middleware/maps/automapper-dto-to-entity-maps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ export const mapComplaintDtoToComplaint = (mapper: Mapper) => {
return { complaint_status_code: status };
}),
),
forMember(
(dest) => dest.comp_mthd_recv_cd_agcy_cd_xref,
mapFrom((src) => {
// This will be looked up from the service using the received complaintMethodReceivedCode
return null; // This will be handled in the service
}),
),
);
};

Expand Down
Loading

0 comments on commit a2671b4

Please sign in to comment.