From 9143b5f524f55139d208f7853bcbf43d8dd99c49 Mon Sep 17 00:00:00 2001 From: "C. Fuhrman" Date: Fri, 21 Feb 2025 14:48:21 -0500 Subject: [PATCH] Revert "Merge pull request #239 from ets-cfuhrman-pfe/revert-217-PFEH25-merge-it2main" This reverts commit 0febb5a394f22713cd5c57aa7d9f6ee4f33fa203, reversing changes made to 687f5be45a5edb398122ccf065d323b330ee8f35. --- .github/workflows/tests.yml | 60 +- .gitignore | 3 + EvalueTonSavoir.code-workspace | 33 ++ client/.eslintrc.cjs | 19 - client/babel.config.cjs | 2 +- client/eslint.config.js | 93 ++- client/jest.config.cjs | 2 +- client/jest.setup.cjs | 2 +- client/package-lock.json | 280 ++++----- client/package.json | 4 + client/src/App.tsx | 96 ++- .../src/__tests__/Types/StudentType.test.tsx | 2 +- .../GiftTemplate/GIFTTemplatePreview.test.tsx | 75 ++- .../components/GiftTemplate/TextType.test.ts | 4 +- .../GiftTemplate/constants/styles.test.tsx | 2 +- .../services/WebsocketService.test.tsx | 14 +- client/src/components/Header/Header.tsx | 14 +- .../StudentModeQuiz/StudentModeQuiz.tsx | 2 +- .../StudentWaitPage/StudentWaitPage.tsx | 2 +- .../TeacherModeQuiz/TeacherModeQuiz.tsx | 2 +- client/src/constants.tsx | 6 +- client/src/pages/AuthManager/AuthDrawer.tsx | 61 ++ client/src/pages/AuthManager/authDrawer.css | 48 ++ .../AuthManager/callback/AuthCallback.tsx | 27 + .../providers/OAuth-Oidc/ButtonAuth.tsx | 27 + .../providers/SimpleLogin/Login.tsx} | 169 +++--- .../providers/SimpleLogin/Register.tsx | 114 ++++ .../providers/SimpleLogin/ResetPassword.tsx | 68 +++ .../AuthManager/providers/css/buttonAuth.css | 23 + .../AuthManager/providers/css/simpleLogin.css | 17 + client/src/pages/Home/home.css | 19 + .../src/pages/Student/JoinRoom/JoinRoom.tsx | 8 +- .../src/pages/Teacher/Dashboard/Dashboard.tsx | 4 +- .../pages/Teacher/EditorQuiz/EditorQuiz.tsx | 3 +- .../pages/Teacher/ManageRoom/ManageRoom.tsx | 3 +- client/src/pages/Teacher/Share/Share.tsx | 2 +- client/src/services/ApiService.tsx | 169 ++++-- client/src/services/AuthService.tsx | 28 + docker-compose-auth.yaml | 96 +++ docker-compose.yaml | 41 +- oauth-tester/config.json | 96 +++ server/.env.example | 8 +- server/.gitignore | 1 + server/__tests__/auth.test.js | 245 ++++++++ server/__tests__/users.test.js | 2 +- server/app.js | 24 +- server/auth/auth-manager.js | 69 +++ .../auth/modules/passport-providers/oauth.js | 100 ++++ .../auth/modules/passport-providers/oidc.js | 106 ++++ server/auth/modules/passportjs.js | 65 +++ server/auth/modules/simpleauth.js | 126 ++++ server/auth_config.json.example | 26 + server/config/auth.js | 193 ++++++ server/constants/errorCodes.js | 7 + server/controllers/auth.js | 36 ++ server/middleware/jwtToken.js | 8 +- server/models/authProvider.js | 44 ++ server/models/authUserAssociation.js | 59 ++ server/models/users.js | 273 +++++---- server/package-lock.json | 548 +++++++++++++++--- server/package.json | 8 +- .../passport-openidconnect+0.1.2.patch | 12 + server/routers/auth.js | 9 + server/routers/users.js | 3 +- server/utils.js | 35 ++ 65 files changed, 3141 insertions(+), 606 deletions(-) create mode 100644 EvalueTonSavoir.code-workspace delete mode 100644 client/.eslintrc.cjs create mode 100644 client/src/pages/AuthManager/AuthDrawer.tsx create mode 100644 client/src/pages/AuthManager/authDrawer.css create mode 100644 client/src/pages/AuthManager/callback/AuthCallback.tsx create mode 100644 client/src/pages/AuthManager/providers/OAuth-Oidc/ButtonAuth.tsx rename client/src/pages/{Teacher/Register/Register.tsx => AuthManager/providers/SimpleLogin/Login.tsx} (63%) create mode 100644 client/src/pages/AuthManager/providers/SimpleLogin/Register.tsx create mode 100644 client/src/pages/AuthManager/providers/SimpleLogin/ResetPassword.tsx create mode 100644 client/src/pages/AuthManager/providers/css/buttonAuth.css create mode 100644 client/src/pages/AuthManager/providers/css/simpleLogin.css create mode 100644 client/src/services/AuthService.tsx create mode 100644 docker-compose-auth.yaml create mode 100644 oauth-tester/config.json create mode 100644 server/.gitignore create mode 100644 server/__tests__/auth.test.js create mode 100644 server/auth/auth-manager.js create mode 100644 server/auth/modules/passport-providers/oauth.js create mode 100644 server/auth/modules/passport-providers/oidc.js create mode 100644 server/auth/modules/passportjs.js create mode 100644 server/auth/modules/simpleauth.js create mode 100644 server/auth_config.json.example create mode 100644 server/config/auth.js create mode 100644 server/controllers/auth.js create mode 100644 server/models/authProvider.js create mode 100644 server/models/authUserAssociation.js create mode 100644 server/patches/passport-openidconnect+0.1.2.patch create mode 100644 server/routers/auth.js create mode 100644 server/utils.js diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d916699..8af0e3b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,29 +8,45 @@ on: branches: - main +env: + MONGO_URI: mongodb://localhost:27017 + MONGO_DATABASE: evaluetonsavoir + jobs: - tests: - runs-on: ubuntu-latest - - steps: - - name: Check Out Repo - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Install Dependencies, lint and Run Tests - run: | - echo "Installing dependencies..." - npm ci - echo "Running ESLint..." - npx eslint . - echo "Running tests..." - npm test - working-directory: ${{ matrix.directory }} - + lint-and-tests: strategy: matrix: directory: [client, server] + fail-fast: false + + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: ${{ matrix.directory }}/package-lock.json + + - name: Process ${{ matrix.directory }} + working-directory: ${{ matrix.directory }} + timeout-minutes: 5 + run: | + echo "::group::Installing dependencies for ${{ matrix.directory }}" + npm ci + echo "::endgroup::" + + echo "::group::Running ESLint" + npx eslint . || { + echo "ESLint failed with exit code $?" + exit 1 + } + echo "::endgroup::" + + echo "::group::Running Tests" + npm test + echo "::endgroup::" + diff --git a/.gitignore b/.gitignore index 6e8de7b..d4eb19a 100644 --- a/.gitignore +++ b/.gitignore @@ -122,6 +122,9 @@ dist # Stores VSCode versions used for testing VSCode extensions .vscode-test +.env +launch.json + # yarn v2 .yarn/cache .yarn/unplugged diff --git a/EvalueTonSavoir.code-workspace b/EvalueTonSavoir.code-workspace new file mode 100644 index 0000000..2ee3b1c --- /dev/null +++ b/EvalueTonSavoir.code-workspace @@ -0,0 +1,33 @@ +{ + "folders": [ + { + "path": "." + }, + { + "name": "server", + "path": "server" + }, + { + "name": "client", + "path": "client" + } + ], + "settings": { + "jest.disabledWorkspaceFolders": [ + "EvalueTonSavoir" + ] + }, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "eslint.validate": [ + "javascript", + "typescript", + "javascriptreact", + "typescriptreact" + ], + // use the same eslint config as `npx eslint` + "eslint.experimental.useFlatConfig": true, + "eslint.nodePath": "./node_modules" + +} diff --git a/client/.eslintrc.cjs b/client/.eslintrc.cjs deleted file mode 100644 index 43f6c4c..0000000 --- a/client/.eslintrc.cjs +++ /dev/null @@ -1,19 +0,0 @@ -// eslint-disable-next-line no-undef -module.exports = { - root: true, - env: { browser: true, es2020: true }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', - ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], - rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - }, -} diff --git a/client/babel.config.cjs b/client/babel.config.cjs index 2bda178..eae7944 100644 --- a/client/babel.config.cjs +++ b/client/babel.config.cjs @@ -1,4 +1,4 @@ -/* eslint-disable no-undef */ + module.exports = { presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'] }; diff --git a/client/eslint.config.js b/client/eslint.config.js index ed8593c..1f5e231 100644 --- a/client/eslint.config.js +++ b/client/eslint.config.js @@ -1,29 +1,78 @@ +import react from "eslint-plugin-react"; +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import typescriptParser from "@typescript-eslint/parser"; import globals from "globals"; import pluginJs from "@eslint/js"; -import tseslint from "typescript-eslint"; -import pluginReact from "eslint-plugin-react"; +import jest from "eslint-plugin-jest"; +import reactRefresh from "eslint-plugin-react-refresh"; +import unusedImports from "eslint-plugin-unused-imports"; +import eslintComments from "eslint-plugin-eslint-comments"; /** @type {import('eslint').Linter.Config[]} */ export default [ - { - files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"], - languageOptions: { - globals: globals.browser, + { + ignores: ["node_modules", "dist/**/*"], }, - rules: { - "no-unused-vars": ["error", { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "caughtErrorsIgnorePattern": "^_" // Ignore catch clause parameters that start with _ - }], - }, - settings: { - react: { - version: "detect", // Automatically detect the React version - }, - }, - }, - pluginJs.configs.recommended, - ...tseslint.configs.recommended, - pluginReact.configs.flat.recommended, + { + files: ["**/*.{js,jsx,mjs,cjs,ts,tsx}"], + languageOptions: { + parser: typescriptParser, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + ...globals.serviceworker, + ...globals.browser, + ...globals.jest, + ...globals.node, + process: "readonly", + }, + }, + plugins: { + "@typescript-eslint": typescriptEslint, + react, + jest, + "react-refresh": reactRefresh, + "unused-imports": unusedImports, + "eslint-comments": eslintComments + }, + rules: { + // Auto-fix unused variables + "@typescript-eslint/no-unused-vars": "off", + "no-unused-vars": "off", + "unused-imports/no-unused-vars": [ + "warn", + { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", + "argsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_" + } + ], + + // Handle directive comments + "eslint-comments/no-unused-disable": "warn", + "eslint-comments/no-unused-enable": "warn", + + // Jest configurations + "jest/valid-expect": ["error", { "alwaysAwait": true }], + "jest/prefer-to-have-length": "warn", + "jest/no-disabled-tests": "off", + "jest/no-focused-tests": "error", + "jest/no-identical-title": "error", + + // React refresh + "react-refresh/only-export-components": ["warn", { + allowConstantExport: true + }], + }, + settings: { + react: { + version: "detect", + }, + }, + } ]; diff --git a/client/jest.config.cjs b/client/jest.config.cjs index 6c635c8..b2d35cc 100644 --- a/client/jest.config.cjs +++ b/client/jest.config.cjs @@ -1,4 +1,4 @@ -/* eslint-disable no-undef */ + /** @type {import('ts-jest').JestConfigWithTsJest} */ module.exports = { diff --git a/client/jest.setup.cjs b/client/jest.setup.cjs index 30fd66a..3b56b65 100644 --- a/client/jest.setup.cjs +++ b/client/jest.setup.cjs @@ -1,3 +1,3 @@ -/* eslint-disable no-undef */ + process.env.VITE_BACKEND_URL = 'http://localhost:4000/'; process.env.VITE_BACKEND_SOCKET_URL = 'https://ets-glitch-backend.glitch.me/'; diff --git a/client/package-lock.json b/client/package-lock.json index 3c24ffc..57b7252 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -23,6 +23,7 @@ "esbuild": "^0.23.1", "gift-pegjs": "^2.0.0-beta.1", "jest-environment-jsdom": "^29.7.0", + "jwt-decode": "^4.0.0", "katex": "^0.16.11", "marked": "^14.1.2", "nanoid": "^5.0.2", @@ -53,9 +54,12 @@ "@typescript-eslint/parser": "^8.5.0", "@vitejs/plugin-react-swc": "^3.7.2", "eslint": "^9.18.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.3", "eslint-plugin-react-hooks": "^5.1.0-rc-206df66e-20240912", "eslint-plugin-react-refresh": "^0.4.12", + "eslint-plugin-unused-imports": "^4.1.4", "globals": "^15.14.0", "identity-obj-proxy": "^3.0.0", "jest": "^29.7.0", @@ -2549,7 +2553,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -2568,7 +2572,7 @@ "version": "4.12.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -2578,7 +2582,7 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.5", @@ -2593,7 +2597,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2604,7 +2608,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -2617,7 +2621,7 @@ "version": "0.10.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz", "integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" @@ -2630,7 +2634,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -2654,7 +2658,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2665,7 +2669,7 @@ "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -2678,7 +2682,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -2691,7 +2695,7 @@ "version": "9.18.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2701,7 +2705,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2711,7 +2715,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz", "integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@eslint/core": "^0.10.0", @@ -2818,7 +2822,7 @@ "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18.18.0" @@ -2828,7 +2832,7 @@ "version": "0.16.6", "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", @@ -2842,7 +2846,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=12.22" @@ -2856,7 +2860,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -3859,7 +3863,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3873,7 +3876,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3887,7 +3889,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3901,7 +3902,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3915,7 +3915,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3929,7 +3928,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3943,7 +3941,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3957,7 +3954,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3971,7 +3967,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3985,7 +3980,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3999,7 +3993,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4013,7 +4006,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4027,7 +4019,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4041,7 +4032,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4055,7 +4045,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4069,7 +4058,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4083,7 +4071,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4097,7 +4084,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4138,7 +4124,7 @@ "version": "1.7.40", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.7.40.tgz", "integrity": "sha512-0HIzM5vigVT5IvNum+pPuST9p8xFhN6mhdIKju7qYYeNuZG78lwms/2d8WgjTJJlzp6JlPguXGrMMNzjQw0qNg==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -4180,7 +4166,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4197,7 +4182,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4214,7 +4198,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -4231,7 +4214,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4248,7 +4230,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4265,7 +4246,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4282,7 +4262,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4299,7 +4278,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4316,7 +4294,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4333,7 +4310,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ @@ -4347,14 +4323,14 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/@swc/types": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.13.tgz", "integrity": "sha512-JL7eeCk6zWCbiYQg2xQSdLXQJl8Qoc9rXmG2cEKvHe3CKwMHwHGpfOb8frzNLmbycOo6I51qxnLnn9ESf4I20Q==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3" @@ -4548,7 +4524,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true, "license": "MIT" }, "node_modules/@types/graceful-fs": { @@ -4648,7 +4623,7 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@types/katex": { @@ -5029,7 +5004,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -5063,7 +5038,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -5138,7 +5113,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, + "devOptional": true, "license": "Python-2.0" }, "node_modules/aria-query": { @@ -5952,7 +5927,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6123,7 +6098,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/deepmerge": { @@ -6673,7 +6648,7 @@ "version": "9.18.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -6729,6 +6704,59 @@ } } }, + "node_modules/eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "engines": { + "node": ">=6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-eslint-comments/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "28.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.11.0.tgz", + "integrity": "sha512-QAfipLcNCWLVocVbZW8GimKn5p5iiMcgGbRzz8z/P5q7xw+cNEpYqyzFMtIF/ZgF2HLOyy+dYBut+DoYolvqig==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "engines": { + "node": "^16.10.0 || ^18.12.0 || >=20.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0 || ^7.0.0 || ^8.0.0", + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { "version": "7.37.4", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", @@ -6827,11 +6855,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-unused-imports": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", + "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", + "dev": true, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", + "eslint": "^9.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, "node_modules/eslint-scope": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -6848,7 +6891,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6861,7 +6904,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=18.18" @@ -6875,7 +6918,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -6886,7 +6929,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6899,7 +6942,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -6912,7 +6955,7 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.14.0", @@ -6930,7 +6973,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -6956,7 +6999,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -6969,7 +7012,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -7062,7 +7105,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-glob": { @@ -7097,14 +7140,14 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fastq": { @@ -7130,7 +7173,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "flat-cache": "^4.0.0" @@ -7184,7 +7227,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -7201,7 +7244,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -7215,7 +7258,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/follow-redirects": { @@ -7480,7 +7523,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -7768,7 +7811,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 4" @@ -7814,7 +7857,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -8317,7 +8360,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -9355,7 +9398,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -9425,7 +9468,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -9438,14 +9481,14 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json5": { @@ -9487,7 +9530,6 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, - "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -9498,6 +9540,14 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "engines": { + "node": ">=18" + } + }, "node_modules/katex": { "version": "0.16.21", "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz", @@ -9517,7 +9567,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -9547,7 +9597,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -9567,7 +9617,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -9604,7 +9654,7 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/longest-streak": { @@ -10381,7 +10431,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/node-int64": { @@ -10561,7 +10611,7 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -10597,7 +10647,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -10613,7 +10663,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -10681,7 +10731,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -10843,7 +10893,6 @@ "version": "8.4.47", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -10872,7 +10921,6 @@ "version": "3.3.8", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "dev": true, "funding": [ { "type": "github", @@ -10891,7 +10939,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -11380,7 +11428,6 @@ "version": "4.24.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.3.tgz", "integrity": "sha512-HBW896xR5HGmoksbi3JBDtmVzWiPAYqp7wip50hjQ67JbDz61nyoMPdqu1DvVW9asYb2M65Z20ZHsyJCMqMyDg==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.6" @@ -11582,7 +11629,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -11595,7 +11642,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -11741,7 +11788,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -11972,7 +12018,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -12240,7 +12286,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -12352,7 +12398,6 @@ "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -12586,7 +12631,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -12675,7 +12720,6 @@ "version": "5.4.14", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", - "dev": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -12813,7 +12857,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12830,7 +12873,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12847,7 +12889,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12864,7 +12905,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12881,7 +12921,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12898,7 +12937,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12915,7 +12953,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12932,7 +12969,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12949,7 +12985,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12966,7 +13001,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12983,7 +13017,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13000,7 +13033,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13017,7 +13049,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13034,7 +13065,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13051,7 +13081,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13068,7 +13097,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13085,7 +13113,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13102,7 +13129,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13119,7 +13145,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13136,7 +13161,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13153,7 +13177,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13170,7 +13193,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13187,7 +13209,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13201,7 +13222,6 @@ "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -13411,7 +13431,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -13515,7 +13535,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13672,7 +13692,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10" diff --git a/client/package.json b/client/package.json index 2a99173..4a49162 100644 --- a/client/package.json +++ b/client/package.json @@ -27,6 +27,7 @@ "esbuild": "^0.23.1", "gift-pegjs": "^2.0.0-beta.1", "jest-environment-jsdom": "^29.7.0", + "jwt-decode": "^4.0.0", "katex": "^0.16.11", "marked": "^14.1.2", "nanoid": "^5.0.2", @@ -57,9 +58,12 @@ "@typescript-eslint/parser": "^8.5.0", "@vitejs/plugin-react-swc": "^3.7.2", "eslint": "^9.18.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-jest": "^28.11.0", "eslint-plugin-react": "^7.37.3", "eslint-plugin-react-hooks": "^5.1.0-rc-206df66e-20240912", "eslint-plugin-react-refresh": "^0.4.12", + "eslint-plugin-unused-imports": "^4.1.4", "globals": "^15.14.0", "identity-obj-proxy": "^3.0.0", "jest": "^29.7.0", diff --git a/client/src/App.tsx b/client/src/App.tsx index 8f8ecf8..9b16e2f 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,6 +1,6 @@ import React from 'react'; -// App.tsx -import { Routes, Route } from 'react-router-dom'; +import { useEffect, useState } from 'react'; +import { Routes, Route, Navigate, useLocation } from 'react-router-dom'; // Page main import Home from './pages/Home/Home'; @@ -8,37 +8,55 @@ import Home from './pages/Home/Home'; // Pages espace enseignant import Dashboard from './pages/Teacher/Dashboard/Dashboard'; import Share from './pages/Teacher/Share/Share'; -import Login from './pages/Teacher/Login/Login'; -import Register from './pages/Teacher/Register/Register'; -import ResetPassword from './pages/Teacher/ResetPassword/ResetPassword'; +import Register from './pages/AuthManager/providers/SimpleLogin/Register'; +import ResetPassword from './pages/AuthManager/providers/SimpleLogin/ResetPassword'; import ManageRoom from './pages/Teacher/ManageRoom/ManageRoom'; import QuizForm from './pages/Teacher/EditorQuiz/EditorQuiz'; // Pages espace étudiant import JoinRoom from './pages/Student/JoinRoom/JoinRoom'; +// Pages authentification selection +import AuthDrawer from './pages/AuthManager/AuthDrawer'; + // Header/Footer import import Header from './components/Header/Header'; import Footer from './components/Footer/Footer'; import ApiService from './services/ApiService'; +import OAuthCallback from './pages/AuthManager/callback/AuthCallback'; -const handleLogout = () => { - ApiService.logout(); -} +const App: React.FC = () => { + const [isAuthenticated, setIsAuthenticated] = useState(ApiService.isLoggedIn()); + const [isTeacherAuthenticated, setIsTeacherAuthenticated] = useState(ApiService.isLoggedInTeacher()); + const [isRoomRequireAuthentication, setRoomsRequireAuth] = useState(null); + const location = useLocation(); -const isLoggedIn = () => { - return ApiService.isLoggedIn(); -} + // Check login status every time the route changes + useEffect(() => { + const checkLoginStatus = () => { + setIsAuthenticated(ApiService.isLoggedIn()); + setIsTeacherAuthenticated(ApiService.isLoggedInTeacher()); + }; + + const fetchAuthenticatedRooms = async () => { + const data = await ApiService.getRoomsRequireAuth(); + setRoomsRequireAuth(data); + }; + + checkLoginStatus(); + fetchAuthenticatedRooms(); + }, [location]); + + const handleLogout = () => { + ApiService.logout(); + setIsAuthenticated(false); + setIsTeacherAuthenticated(false); + }; -function App() { return (
- -
- +
@@ -46,22 +64,46 @@ function App() { } /> {/* Pages espace enseignant */} - } /> - } /> - } /> - } /> - } /> - } /> - } /> + : } + /> + : } + /> + : } + /> + : } + /> {/* Pages espace étudiant */} - } /> + : } + /> + + {/* Pages authentification */} + } /> + + {/* Pages enregistrement */} + } /> + + {/* Pages rest password */} + } /> + + {/* Pages authentification sélection */} + } />
-
+
); -} +}; export default App; diff --git a/client/src/__tests__/Types/StudentType.test.tsx b/client/src/__tests__/Types/StudentType.test.tsx index 4e7c849..2f9efbe 100644 --- a/client/src/__tests__/Types/StudentType.test.tsx +++ b/client/src/__tests__/Types/StudentType.test.tsx @@ -12,6 +12,6 @@ describe('StudentType', () => { expect(user.name).toBe('Student'); expect(user.id).toBe('123'); - expect(user.answers.length).toBe(0); + expect(user.answers).toHaveLength(0); }); }); diff --git a/client/src/__tests__/components/GiftTemplate/GIFTTemplatePreview.test.tsx b/client/src/__tests__/components/GiftTemplate/GIFTTemplatePreview.test.tsx index 586c8d1..967d33c 100644 --- a/client/src/__tests__/components/GiftTemplate/GIFTTemplatePreview.test.tsx +++ b/client/src/__tests__/components/GiftTemplate/GIFTTemplatePreview.test.tsx @@ -5,47 +5,64 @@ import GIFTTemplatePreview from 'src/components/GiftTemplate/GIFTTemplatePreview describe('GIFTTemplatePreview Component', () => { test('renders error message when questions contain invalid syntax', () => { - render(); - const errorMessage = screen.findByText(/Erreur inconnue/i, {}, { timeout: 5000 }); - expect(errorMessage).resolves.toBeInTheDocument(); + render(); + const errorMessage = screen.getByText(/Title ::, Category, Description, or Question formatted stem but ":" found./i); + expect(errorMessage).toBeInTheDocument(); }); + test('renders preview when valid questions are provided', () => { const questions = [ - 'Question 1 { A | B | C }', - 'Question 2 { D | E | F }', + 'Stem1 {=ans1 ~ans2 ~ans3}', ]; render(); const previewContainer = screen.getByTestId('preview-container'); expect(previewContainer).toBeInTheDocument(); + // const question1 = screen.getByText('Stem1'); + const mcQuestion1 = screen.getByText('Stem1'); + const ans1 = screen.getByText('ans1'); + const ans2 = screen.getByText('ans2'); + const ans3 = screen.getByText('ans3'); + expect(mcQuestion1).toBeInTheDocument(); + expect(ans1).toBeInTheDocument(); + expect(ans2).toBeInTheDocument(); + expect(ans3).toBeInTheDocument(); + + // each answer should have a radio button before it + const radioButtons = screen.getAllByRole('radio'); + expect(radioButtons).toHaveLength(3); + // ans1 should be the