Skip to content

Commit

Permalink
PIMS-2027 BCSC Provider Options (#2675)
Browse files Browse the repository at this point in the history
Co-authored-by: LawrenceLau2020 <[email protected]>
Co-authored-by: Lawrence Lau <[email protected]>
  • Loading branch information
3 people authored Sep 18, 2024
1 parent 8e210c5 commit 2aa895d
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 17 deletions.
3 changes: 3 additions & 0 deletions express-api/src/constants/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ const config = {
title: 'PIMS',
uri: process.env.FRONTEND_URL,
},
keycloak: {
client_id: process.env.SSO_CLIENT_ID,
},
};

const getConfig = () => {
Expand Down
1 change: 1 addition & 0 deletions express-api/src/controllers/lookup/lookupController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ export const lookupAll = async (req: Request, res: Response) => {
),
Config: {
contactEmail: cfg.contact.toEmail,
bcscIdentifier: cfg.keycloak.client_id,
},
};
return res.status(200).send(returnObj);
Expand Down
2 changes: 2 additions & 0 deletions express-api/src/routes/lookup.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ components:
contactEmail:
type: string
example: [email protected]
bcscIdentifier:
type: string
ConstructionTypes:
type: array
items:
Expand Down
3 changes: 2 additions & 1 deletion express-api/src/typeorm/Entities/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ export class User extends BaseEntity {
@Column({ type: 'timestamp', nullable: true })
ApprovedOn: Date;

@Column({ type: 'uuid', nullable: true })
// Using varchar instead of uuid because some providers use characters outside [0-9a-f]
@Column({ type: 'character varying', nullable: true, length: 36 })
KeycloakUserId: string;

// Agency Relations
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class KeycloakUserIdType1726615038425 implements MigrationInterface {
name = 'KeycloakUserIdType1726615038425';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "user" ALTER COLUMN keycloak_user_id TYPE CHARACTER VARYING(36) USING keycloak_user_id::TEXT;`,
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "user" ALTER COLUMN keycloak_user_id TYPE UUID USING keycloak_user_id::UUID;`,
);
}
}
10 changes: 8 additions & 2 deletions react-app/src/components/users/UserDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useParams } from 'react-router-dom';
import useDataSubmitter from '@/hooks/useDataSubmitter';
import { Role, Roles } from '@/constants/roles';
import { LookupContext } from '@/contexts/lookupContext';
import { getProvider } from '@/utilities/helperFunctions';

interface IUserDetail {
onClose: () => void;
Expand Down Expand Up @@ -50,8 +51,13 @@ const UserDetail = ({ onClose }: IUserDetail) => {
Role: lookupData?.Roles?.find((role) => role.Id === data?.RoleId),
};

const provider = useMemo(
() => getProvider(data?.Username, lookupData?.Config.bcscIdentifier),
[data],
);

const userProfileData = {
Provider: data?.Username.includes('idir') ? 'IDIR' : 'BCeID',
Provider: provider,
Email: data?.Email,
FirstName: data?.FirstName,
LastName: data?.LastName,
Expand Down Expand Up @@ -102,7 +108,7 @@ const UserDetail = ({ onClose }: IUserDetail) => {

useEffect(() => {
profileFormMethods.reset({
Provider: data?.Username.includes('idir') ? 'IDIR' : 'BCeID',
Provider: provider,
Email: userProfileData.Email,
FirstName: userProfileData.FirstName,
LastName: userProfileData.LastName,
Expand Down
13 changes: 2 additions & 11 deletions react-app/src/components/users/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Agency } from '@/hooks/api/useAgencyApi';
import { User } from '@/hooks/api/useUsersApi';
import { LookupContext } from '@/contexts/lookupContext';
import { Role } from '@/constants/roles';
import { getProvider } from '@/utilities/helperFunctions';

const CustomMenuItem = (props: PropsWithChildren & { value: string }) => {
const theme = useTheme();
Expand Down Expand Up @@ -175,17 +176,7 @@ const UsersTable = (props: IUsersTable) => {
field: 'Username',
headerName: 'Provider',
width: 125,
valueGetter: (value) => {
const username: string = value;
if (username && !username.includes('@')) return undefined;
const provider = username.split('@').at(1);
switch (provider) {
case 'idir':
return 'IDIR';
default:
return 'BCeID';
}
},
valueGetter: (value) => getProvider(value, lookup?.data?.Config.bcscIdentifier),
},
{
field: 'Agency',
Expand Down
1 change: 1 addition & 0 deletions react-app/src/hooks/api/useLookupApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export interface LookupAll {
RegionalDistricts: Partial<RegionalDistrict>[];
Config: {
contactEmail: string;
bcscIdentifier?: string;
};
}

Expand Down
25 changes: 22 additions & 3 deletions react-app/src/pages/AccessRequest.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from 'react';
import React, { useContext, useEffect, useMemo } from 'react';
import pendingImage from '@/assets/images/pending.svg';
import { Box, Button, Grid, Paper, Typography } from '@mui/material';
import AutocompleteFormField from '@/components/form/AutocompleteFormField';
Expand All @@ -18,6 +18,7 @@ import TextFormField from '@/components/form/TextFormField';
import { useGroupedAgenciesApi } from '@/hooks/api/useGroupedAgenciesApi';
import { SnackBarContext } from '@/contexts/snackbarContext';
import { LookupContext } from '@/contexts/lookupContext';
import { getProvider } from '@/utilities/helperFunctions';

interface StatusPageTemplateProps {
blurb: JSX.Element;
Expand All @@ -41,10 +42,16 @@ const StatusPageTemplate = (props: StatusPageTemplateProps) => {
const RequestForm = ({ submitHandler }: { submitHandler: (d: any) => void }) => {
const keycloak = useSSO();
const agencyOptions = useGroupedAgenciesApi().agencyOptions;
const lookup = useContext(LookupContext);

const provider = useMemo(
() => getProvider(keycloak.user?.preferred_username, lookup?.data?.Config.bcscIdentifier),
[keycloak.user, lookup],
);

const formMethods = useForm({
defaultValues: {
UserName: keycloak.user?.username,
Provider: provider,
FirstName: keycloak.user?.first_name,
LastName: keycloak.user?.last_name,
Email: keycloak.user?.email,
Expand All @@ -54,12 +61,24 @@ const RequestForm = ({ submitHandler }: { submitHandler: (d: any) => void }) =>
},
});

useEffect(() => {
formMethods.reset({
Provider: provider,
FirstName: keycloak.user?.first_name || '',
LastName: keycloak.user?.last_name || '',
Email: keycloak.user?.email || '',
Notes: '',
Agency: '',
Position: '',
});
}, [provider, keycloak.user]);

return (
<>
<FormProvider {...formMethods}>
<Grid spacing={2} container>
<Grid item xs={6}>
<TextFormField fullWidth name={'UserName'} label={'IDIR/BCeID'} disabled />
<TextFormField fullWidth name={'Provider'} label={'Provider'} disabled />
</Grid>
<Grid item xs={6}>
<TextFormField fullWidth name={'Email'} label={'Email'} disabled />
Expand Down
20 changes: 20 additions & 0 deletions react-app/src/utilities/helperFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,23 @@ export const getValueByNestedKey = <T extends Record<string, any>>(obj: T, key:
}
return result;
};

/**
* Returns the provider based on the username and optional BCSC identifier.
* @param username The username to check for provider information.
* @param bcscIdentifier The optional BCSC identifier to check for BCSC provider.
* @returns The provider name ('IDIR', 'BCeID', 'BCSC') based on the username or an empty string if no match.
*/
export const getProvider = (username: string, bcscIdentifier?: string) => {
if (!username) return '';
switch (true) {
case username.includes('idir'):
return 'IDIR';
case username.includes('bceid'):
return 'BCeID';
case username.includes(bcscIdentifier):
return 'BC Services Card';
default:
return '';
}
};

0 comments on commit 2aa895d

Please sign in to comment.