From 92aafa1b8710fcb8c936f0e16d0588660cdb46c1 Mon Sep 17 00:00:00 2001 From: Ariel Rotter-Aboyoun Date: Wed, 4 Dec 2024 13:19:11 -0800 Subject: [PATCH 01/21] Draft w/ changes --- backend/package-lock.json | 24 ++++++++--- backend/package.json | 1 + backend/src/express.ts | 9 ++++ backend/src/middleware/globalErrorHandler.ts | 23 ++++++++++ backend/src/middleware/index.ts | 2 + docker-compose.yml | 6 ++- frontend/package-lock.json | 11 +++++ frontend/package.json | 1 + .../src/components/common/Header/Header.tsx | 23 ++++++++++ frontend/src/main.tsx | 12 ++++-- frontend/vite.config.ts | 42 +++++++++++++++---- 11 files changed, 135 insertions(+), 19 deletions(-) create mode 100644 backend/src/middleware/globalErrorHandler.ts create mode 100644 backend/src/middleware/index.ts diff --git a/backend/package-lock.json b/backend/package-lock.json index c139668..d881241 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@bcgov/citz-imb-sso-express": "^1.0.2", "compression": "^1.7.4", "cookie-parser": "^1.4.6", "cors": "^2.8.5", @@ -758,6 +759,17 @@ "node": ">=6.9.0" } }, + "node_modules/@bcgov/citz-imb-sso-express": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcgov/citz-imb-sso-express/-/citz-imb-sso-express-1.0.2.tgz", + "integrity": "sha512-I6p6mSg2dr6/ySYclotJhqTIJ3hbw++G3w4kZQn96dYRLjbSV+qOtWMWjFZWmMUq/KRES/OITho30az1fOh9VQ==", + "license": "Apache-2.0", + "dependencies": { + "cookie-parser": "1.4.6", + "cors": "2.8.5", + "express": "4.19.2" + } + }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", @@ -3258,9 +3270,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -6813,9 +6825,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/backend/package.json b/backend/package.json index a202b3c..5ad02cb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -42,6 +42,7 @@ "typescript-eslint": "^7.8.0" }, "dependencies": { + "@bcgov/citz-imb-sso-express": "^1.0.2", "compression": "^1.7.4", "cookie-parser": "^1.4.6", "cors": "^2.8.5", diff --git a/backend/src/express.ts b/backend/src/express.ts index 7f298c5..275f880 100644 --- a/backend/src/express.ts +++ b/backend/src/express.ts @@ -13,11 +13,15 @@ import morgan from 'morgan'; import cors from 'cors'; import swaggerUi from 'swagger-ui-express'; import swaggerJSDoc from 'swagger-jsdoc'; +import { protectedRoute, sso } from '@bcgov/citz-imb-sso-express'; import swaggerConfig from './config/swaggerConfig'; import * as routers from './routes/index'; +import * as middleware from './middleware'; const app = express(); +sso(app); + // Express middleware app.use(express.json()); app.use(express.urlencoded({ extended: false })); @@ -27,7 +31,12 @@ app.use(morgan('dev')); // Logger Requests and Responses in the console app.use(cors()); // Activate CORS, allowing access app.use('/api/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerJSDoc(swaggerConfig))); +// Add the protectedRoute function to any endpoint routes in the Admin Portal + // Routes app.use('/api', [routers.healthRouter, routers.developersRouter]); +// Integrate global error handler after routes to cover all ends. +app.use(middleware.globalErrorHandler); + export default app; diff --git a/backend/src/middleware/globalErrorHandler.ts b/backend/src/middleware/globalErrorHandler.ts new file mode 100644 index 0000000..6dc44ee --- /dev/null +++ b/backend/src/middleware/globalErrorHandler.ts @@ -0,0 +1,23 @@ +import { Request, Response, NextFunction } from 'express'; +/** + * PURPOSE: Global Error Handler is in place to give more meaningful communication with + * the user if something in the application goes wrong + */ + +type Props = { + req: Request; + res: Response; + next: NextFunction; +} + +const globalErrorHandler = ({ + res, + next, +}: Props) => { + res.status(500).json({ + message: 'Internal Server Error', + }); + next(); +}; + +export default globalErrorHandler; \ No newline at end of file diff --git a/backend/src/middleware/index.ts b/backend/src/middleware/index.ts new file mode 100644 index 0000000..fd9fe62 --- /dev/null +++ b/backend/src/middleware/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/prefer-default-export +export { default as globalErrorHandler } from './globalErrorHandler'; \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index bef0ca1..a7d3ed0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,6 +50,7 @@ services: path: ./backend/ target: app ignore: [node_modules] + env_file: .env environment: LOG_LEVEL: info PORT: 3000 @@ -72,8 +73,9 @@ services: # path: ./frontend # target: /app # ignore: [node_modules] - environment: - VITE_BACKEND_URL: http://localhost:3000/api + env_file: .env + # environment: + # VITE_BACKEND_URL: http://localhost:3000 healthcheck: test: curl --fail http://localhost:5173 || exit 1 ports: ["5173:5173"] diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f02382c..6712e57 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@bcgov/bc-sans": "^2.1.0", + "@bcgov/citz-imb-sso-react": "^1.0.1", "@bcgov/design-tokens": "^3.1.1", "@emotion/styled": "^11.13.0", "axios": "^1.7.7", @@ -337,6 +338,16 @@ "resolved": "https://registry.npmjs.org/@bcgov/bc-sans/-/bc-sans-2.1.0.tgz", "integrity": "sha512-1MesF4NAVpM5dywoJ68wNcBylHbPqg1dDV/FNuQm0BbspETGlPmfX8LG8rtrCjCAPhWuL2qRT/lBYDUMvFTUnw==" }, + "node_modules/@bcgov/citz-imb-sso-react": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bcgov/citz-imb-sso-react/-/citz-imb-sso-react-1.0.1.tgz", + "integrity": "sha512-Bg3SVDlLvWeuPHgriY4KjPICxbAle8UFetFdlWE6ig/VjIo8C18ogUptMjEX1rZtwtd/AP4wfL36apLyLVOzrw==", + "license": "Apache-2.0", + "dependencies": { + "@bcgov/bc-sans": "2.1.0", + "react": "18.3.1" + } + }, "node_modules/@bcgov/design-tokens": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@bcgov/design-tokens/-/design-tokens-3.1.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index a569c27..d5d0d69 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@bcgov/bc-sans": "^2.1.0", + "@bcgov/citz-imb-sso-react": "^1.0.1", "@bcgov/design-tokens": "^3.1.1", "@emotion/styled": "^11.13.0", "axios": "^1.7.7", diff --git a/frontend/src/components/common/Header/Header.tsx b/frontend/src/components/common/Header/Header.tsx index 96535ae..fb8dde9 100644 --- a/frontend/src/components/common/Header/Header.tsx +++ b/frontend/src/components/common/Header/Header.tsx @@ -1,12 +1,25 @@ /** * @summary Reusable BC Gov Header Component */ +import { useSSO } from '@bcgov/citz-imb-sso-react'; import logo from '/logo-banner.svg'; // import { Link } from 'react-router-dom'; import { HeaderWrapper, Heading, Banner, Image, StyledLink } from './header.styles'; +import { Button } from '../Button/Button'; +import { ButtonWrapper } from '../../../views/LandingPage/landingPage.styles'; export default function Header() { + const { login, logout, isAuthenticated } = useSSO(); + + const handleLoginButton = () => { + if (isAuthenticated) { + logout(); + } else { + login({ backendURL: 'http://localhost:3000', idpHint: 'idir', postLoginRedirectURL: '/' }); + } + }; + return ( @@ -17,6 +30,16 @@ export default function Header() { Nutrient Management Calculator + +