Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: kc gold integration #2135

Merged
merged 35 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1fa7c55
refactor: jwt_token type has a sub of type text
pbastia Jan 11, 2023
7173bb3
refactor: trigger to disallow user update under certain conditions
pbastia Jan 11, 2023
3b27c65
refactor: revert functions
pbastia Jan 11, 2023
0ab3acf
refactor: rename immutable flag function
pbastia Jan 12, 2023
5c1b55a
refactor: dropping policies before changing the uuid type
pbastia Jan 12, 2023
f4dc142
refactor: ciip_user table with a uuid of type text
pbastia Jan 12, 2023
19dbdac
refactor: updating set_user_id trigger with text type for uuid
pbastia Jan 12, 2023
dc2fa04
refactor: update_timestamps doesnt depend on a uuid type
pbastia Jan 12, 2023
58dd768
refactor: re-adding the policies removed before the change
pbastia Jan 12, 2023
105a0e1
refactor: session middleware
pbastia Jan 13, 2023
c928859
chore: updating nodejs
pbastia Jan 13, 2023
b8125df
refactor: using sso-express to login with the new kc gold instance
pbastia Jan 13, 2023
2220fed
test: update tests for cif_user table
dleard Jan 13, 2023
1f2e626
refactor: removing obsolete registration buttons
pbastia Jan 13, 2023
7154fec
chore: removing default create_user mutation
pbastia Jan 14, 2023
e96dd1e
refactor: custom create user mutation that reconciles users
pbastia Jan 14, 2023
125c2c4
refactor: user form calls the custom mutation
pbastia Jan 14, 2023
8eeb8a1
test: frontend test updates
pbastia Jan 14, 2023
0c0311e
test: starting to write tests for the create user mutation
pbastia Jan 14, 2023
4b23b58
refactor: rejecting all accepted or pending access requests
pbastia Jan 16, 2023
8d79130
test: testing mutation adding or updating user upon login
pbastia Jan 16, 2023
692d334
test: testing the update uuid function
pbastia Jan 16, 2023
21b9800
test: updating login page e2e
pbastia Jan 16, 2023
0230ea2
chore: pre-commit
pbastia Jan 16, 2023
96e9e40
test: e2e redirects
pbastia Jan 17, 2023
f94bc6d
fix: session idled message is not displayed when user tries to login
pbastia Jan 17, 2023
68b086e
refactor: sqitch verify
pbastia Jan 17, 2023
c2c7d76
chore: flagging false positive in env example file
pbastia Jan 17, 2023
a1bd298
chore: eslint fixes and removing unused dependencies
pbastia Jan 17, 2023
3139400
chore: schema files
pbastia Jan 17, 2023
a7bf7a2
chore: pre-commit errors
pbastia Jan 17, 2023
506f429
chore: removing sqitch verify after db deploy in ci
pbastia Jan 18, 2023
2756ea9
chore: removing unnecessary permissions
pbastia Jan 19, 2023
0f4c2fc
chore: reworks are now migrations
pbastia Jan 19, 2023
8769427
chore: yarn lockfile after rebase
pbastia Jan 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,6 @@ jobs:
source ~/.bashrc
pushd schema
./data/deploy-data.sh -prod
sqitch verify
popd
- run:
name: regenerate schema via introspection
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
nodejs 14.17.5
nodejs 14.21.1
yarn 1.22.19
postgres 14.0
python 3.9.2
2 changes: 2 additions & 0 deletions app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ HOST=<host address>
GGIRCS_HOST=<ggircs URL>
METABASE_HOST=<metabase URL>

KC_CLIENT_SECRET=<keycloak client secret> #pragma: allowlist secret

# true if we want the mocks database schema to be deployed, false otherwise
ENABLE_DB_MOCKS=<true or false>
ENABLE_DB_MOCKS_COOKIES_ONLY=<true or false>
Expand Down
7 changes: 1 addition & 6 deletions app/components/Layout/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,10 @@ const HeaderLayout: React.FunctionComponent<Props> = ({
isRegistered && userProfileDropdown
) : (
<>
<li>
<Link href="/register">
<a className="nav-button">Register</a>
</Link>
</li>
<li>
<LoginButton>
<button className="nav-button" type="submit">
Login
Login (IDIR)
</button>
</LoginButton>
</li>
Expand Down
4 changes: 2 additions & 2 deletions app/components/LoginButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { Form } from "react-bootstrap";

const LoginForm: React.FunctionComponent = ({ children }) => {
const router = useRouter();
let loginURI = "/login";
let loginURI = "/login?kc_idp_hint=idir";

if (router.query.redirectTo)
loginURI += `?redirectTo=${encodeURIComponent(
loginURI += `&redirectTo=${encodeURIComponent(
router.query.redirectTo as string
)}`;

Expand Down
16 changes: 2 additions & 14 deletions app/containers/RegistrationLoginButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react";
import { Col, Card, Button } from "react-bootstrap";
import LoginButton from "../components/LoginButton";
import { Col, Card } from "react-bootstrap";
import { createFragmentContainer, graphql } from "react-relay";
import { RegistrationLoginButtons_query } from "RegistrationLoginButtons_query.graphql";
import { dateTimeFormat } from "functions/formatDates";
Expand Down Expand Up @@ -46,20 +45,9 @@ export const RegistrationLoginButtonsComponent: React.FunctionComponent<Props> =
Apply for the CleanBC Industrial Incentive Program (CIIP)
</Card.Title>
{cardText}
<a
href="/register"
style={{ padding: "15px", display: "block" }}
className="btn btn-primary btn-lg"
>
Register and Apply
</a>
</Card.Body>
</Card>
<LoginButton>
<Button className="login-link" type="submit" variant="outline-dark">
Already have an account? Click here to login.
</Button>
</LoginButton>

<style jsx global>{`
.login-link {
padding: 20px;
Expand Down
103 changes: 50 additions & 53 deletions app/containers/User/UserForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState } from "react";
import React, { useMemo } from "react";
import { createFragmentContainer, graphql, RelayProp } from "react-relay";
import JsonSchemaForm, { IChangeEvent, AjvError } from "@rjsf/core";
import { JSONSchema7 } from "json-schema";
import { UserForm_user } from "UserForm_user.graphql";
import createUserMutation from "mutations/user/createUserMutation";
import createOrUpdateUserMutation from "mutations/user/createOrUpdateUserMutation";
import updateUserMutation from "mutations/user/updateUserMutation";
import FormArrayFieldTemplate from "containers/Forms/FormArrayFieldTemplate";
import FormFieldTemplate from "containers/Forms/FormFieldTemplate";
Expand All @@ -13,7 +13,6 @@ import { customTransformErrors } from "functions/customTransformErrors";
interface Props {
user?: UserForm_user;
relay: RelayProp;
uuid?: string;
defaultGivenName?: string;
defaultFamilyName?: string;
defaultEmail?: string;
Expand All @@ -37,7 +36,6 @@ const transformErrors = (errors: AjvError[]) => {

const UserForm: React.FunctionComponent<Props> = ({
user,
uuid,
defaultGivenName,
defaultFamilyName,
defaultEmail,
Expand All @@ -46,20 +44,13 @@ const UserForm: React.FunctionComponent<Props> = ({
}) => {
const handleChange = async (e: IChangeEvent<UserForm_user>) => {
if (user) {
const {
firstName,
lastName,
emailAddress,
phoneNumber,
occupation,
} = e.formData;
const { firstName, lastName, phoneNumber, occupation } = e.formData;
await updateUserMutation(relay.environment, {
input: {
id: user.id,
ciipUserPatch: {
firstName,
lastName,
emailAddress,
phoneNumber,
occupation,
},
Expand All @@ -70,62 +61,68 @@ const UserForm: React.FunctionComponent<Props> = ({

const handleSubmit = async (e: IChangeEvent<UserForm_user>) => {
if (user) await handleChange(e);
else
await createUserMutation(relay.environment, {
else {
const { firstName, lastName, phoneNumber, occupation } = e.formData;
await createOrUpdateUserMutation(relay.environment, {
input: {
ciipUser: {
...e.formData,
uuid,
},
firstName,
lastName,
phoneNumber,
occupation,
},
});
}
onSubmit();
};

const [userSchema] = useState<JSONSchema7>({
type: "object",
properties: {
firstName: {
type: "string",
title: "First Name",
default: defaultGivenName,
},
lastName: {
type: "string",
title: "Last Name",
default: defaultFamilyName,
},
emailAddress: {
type: "string",
title: "Email Address",
default: defaultEmail,
format: "email",
},
phoneNumber: {
type: "string",
title: "Phone Number",
format: "phoneNumber",
},
occupation: {
type: "string",
title: "Occupation",
const userSchema: JSONSchema7 = useMemo(
() => ({
type: "object",
properties: {
firstName: {
type: "string",
title: "First Name",
default: defaultGivenName,
},
lastName: {
type: "string",
title: "Last Name",
default: defaultFamilyName,
},
emailAddress: {
type: "string",
title: "Email Address",
default: defaultEmail,
format: "email",
},
phoneNumber: {
type: "string",
title: "Phone Number",
format: "phoneNumber",
},
occupation: {
type: "string",
title: "Occupation",
},
},
required: ["firstName", "lastName", "phoneNumber", "occupation"],
}),
[defaultGivenName, defaultFamilyName, defaultEmail]
);

const uiSchema = {
emailAddress: {
"ui:disabled": true,
},
required: [
"firstName",
"lastName",
"emailAddress",
"phoneNumber",
"occupation",
],
});
};

return (
<JsonSchemaForm
omitExtraData
liveOmit
liveValidate
schema={userSchema}
uiSchema={uiSchema}
customFormats={customFormats}
transformErrors={transformErrors}
formData={user}
Expand Down
12 changes: 6 additions & 6 deletions app/cypress/integration/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ describe("The index page", () => {

cy.visit("/");
cy.get("#page-content");
cy.get("header").contains("Register");
cy.get("header").contains("Login");
cy.get("header").contains("Register").should("not.exist");
cy.get("header").contains("Login (IDIR)");
cy.get("header").happoScreenshot({ component: "Header" });
cy.get("footer").happoScreenshot({ component: "Footer" });
cy.get("#page-content").contains("Register and Apply");
cy.get("#page-content").contains(
"Already have an account? Click here to login."
);
cy.get("#page-content").contains("Register and Apply").should("not.exist");
cy.get("#page-content")
.contains("Already have an account? Click here to login.")
.should("not.exist");

cy.contains("Jan 23, 1991");
cy.get("body").happoScreenshot({ component: "Index Page" });
Expand Down
12 changes: 1 addition & 11 deletions app/cypress/integration/login-redirects.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ function testRedirectsForScopedPages(scope, pages) {

cy.mockLogin(scope);

// As the SSO login page won't open in a frame in Cypress, the final redirect must be
// tested indirectly as though we're following the auth callback:
cy.visit(`/login?redirectTo=${encodeURIComponent(url)}`);
cy.visit(url);
cy.url().should("include", url);
});
});
Expand All @@ -62,11 +60,3 @@ describe("Successful redirection of authenticated pages through login", () => {
testRedirectsForScopedPages(scope, AUTHENTICATED_PAGES[scope])
);
});

describe("When failing the keycloak authorization", () => {
it("should redirect to the 403 page", () => {
// Any request with the auth_callback=1 query param will be routed through the keycloak middleware
cy.visit("/login?auth_callback=1");
cy.url().should("include", "/403");
});
});
5 changes: 0 additions & 5 deletions app/data/kc-namespace-map.json

This file was deleted.

32 changes: 32 additions & 0 deletions app/mutations/user/createOrUpdateUserMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { graphql } from "react-relay";
import {
createOrUpdateUserMutation as createOrUpdateUserMutationType,
createOrUpdateUserMutationVariables,
} from "__generated__/createOrUpdateUserMutation.graphql";
import RelayModernEnvironment from "relay-runtime/lib/store/RelayModernEnvironment";
import BaseMutation from "mutations/BaseMutation";

const mutation = graphql`
mutation createOrUpdateUserMutation($input: CreateOrUpdateCiipUserInput!) {
createOrUpdateCiipUser(input: $input) {
ciipUser {
firstName
lastName
emailAddress
occupation
phoneNumber
}
}
}
`;

const createOrUpdateUserMutation = async (
environment: RelayModernEnvironment,
variables: createOrUpdateUserMutationVariables
) => {
return new BaseMutation<createOrUpdateUserMutationType>(
"create-or-update-ciip-user-mutation"
).performMutation(environment, mutation, variables);
};

export default createOrUpdateUserMutation;
32 changes: 0 additions & 32 deletions app/mutations/user/createUserMutation.ts

This file was deleted.

5 changes: 3 additions & 2 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@
"lint": "eslint --ext .js,.jsx,.ts,.tsx ."
},
"engines": {
"node": "14.17.5",
"node": "14.21.1",
"yarn": "1.22.19"
},
"author": "",
"license": "ISC",
"dependencies": {
"@bcgov-cas/sso-express": "^3.2.0",
"@fortawesome/fontawesome-svg-core": "^1.2.31",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.1.16",
Expand Down Expand Up @@ -61,13 +62,13 @@
"isomorphic-fetch": "^3.0.0",
"js-file-download": "^0.4.12",
"json-schema": "^0.4.0",
"keycloak-connect": "^10.0.0",
"lightship": "^6.7.2",
"lodash.throttle": "^4.1.1",
"moment-timezone": "^0.5.35",
"morgan": "^1.10.0",
"next": "^12.1.0",
"nodemailer": "^6.6.1",
"openid-client": "5",
"pg": "^8.2.0",
"postgraphile": "^4.11.0",
"postgraphile-log-consola": "^1.0.1",
Expand Down
Loading